I want to get my sended errors from data.errors. I use "https://github.com/zino-app/graphql-flutter/tree/master/packages/graphql" to get my response. My response look like this:
{data: {…}, status: 401, statusText: "OK", headers: {…}, config: {…}, …}
config: {url: "http://localhost:3000/graphql", method: "post", data: "{"query":"\n query getSomeData($date: Str…variables":{"date":"2020-09-18","city":"London"}}", headers: {…}, transformRequest: Array(1), …}
data:
data: {getSomeData: null}
errors: [{…}]
__proto__: Object
headers: {content-length: "88", content-type: "application/json; charset=utf-8"}
original_status: 200
request: XMLHttpRequest {readyState: 4, timeout: 0, withCredentials: false, upload: XMLHttpRequestUpload, onreadystatechange: ƒ, …}
status: 401
statusText: "OK"
__proto__: Object
My code to get my data looks like:
import 'dart:async';
import 'package:graphql/client.dart';
import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import '../shared/secure_storage.dart' as storage;
final HttpLink _httpLink = HttpLink(
uri: DotEnv().env['BACKEND_CONNECTION'],
);
final AuthLink _authLink = AuthLink(
getToken: () async => 'Bearer ' + storage.getToken(),
);
final Link _link = _authLink.concat(_httpLink);
final GraphQLClient _client = GraphQLClient(
cache: InMemoryCache(),
link: _link,
);
final String query = ''' typical query''';
class PublicConcertsBloc extends ChangeNotifier {
//Data
List _result;
List get result => _result;
//Getters
QueryOptions get options => QueryOptions(
documentNode: gql(query), variables: {'var1': var, 'var2': 'var2'});
set result(List val) {
_result = val;
notifyListeners();
}
Future loadConcerts() async {
final QueryResult result = await _client.query(options);
if (result.data == null) {
print("data == null");
} else if (result.data["getSomeData"] == null) {
print("getSomeData == getSomeData");
} else if (result.loading) {
print(result.loading.toString());
} else if (result.hasException) {
print(result.exception.toString());
} else {
print(result.data['getSomeData']);
_result = result.data['getSomeData'] as List;
}
}
}
Can someone help me here? result.exception dont show me the wanted erros.
The error is provided on the HTTP Response - which is 401. This status code is thrown due to an unauthenticated HTTP Request. The reason why QueryResult.exception is empty was because the HTTP Request was successfully executed.
Related
I'm writing a Unit test for my data source and face the problem No stub was found which matches the arguments of this method call
import 'dart:convert';
import 'package:dartz/dartz.dart';
import 'package:dio/dio.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'package:true_food/core/constant.dart';
import 'package:true_food/core/network_manager.dart';
import 'package:true_food/features/home/data/datasources/home_data_source.dart';
import 'package:true_food/features/home/data/models/shelve.dart';
import 'package:true_food/features/home/data/models/shelve_banner_list.dart';
import 'package:true_food/features/home/domain/entities/banner_list_request_model.dart';
import '../../../../core/utils/fixture_reader.dart';
import 'home_data_source_test.mocks.dart';
#GenerateMocks([NetworkManager])
main() {
late HomeDataSourceImpl dataSource;
late MockNetworkManager mockNetworkManager;
final successCode = 201;
final shelveUrl = Constant.baseUrl + APIRoute.shelveList;
final bannerUrl = Constant.baseUrl + APIRoute.bannerList;
setUp(() {
mockNetworkManager = MockNetworkManager();
dataSource = HomeDataSourceImpl(mockNetworkManager);
});
void onCallSuccess(Function body) {
group('Get list successfully', () {
body();
});
}
void onCallFailed(Function body) {
group('Get list unsuccessfully', () {
body();
});
}
BannerListRequestModel request = const BannerListRequestModel(
url:
"/weshop/api/TRUEID_TRUEFOOD/shelfContent?type=item&sort=sequence&itemGroup=6183b134b6d93f000180bf76&page={sys.page}&size={sys.size}&publishStatus=true",
location: BannerListRequestLocationModel(latitude: 0.0, longitude: 0.0),
page: 0,
size: 4);
Future<void> makeResponseSuccessfull(dynamic data) async {
final Response response =
Response(requestOptions: RequestOptions(path: 'path'), statusCode: 200);
when(mockNetworkManager.request(
path: shelveUrl,
method: Method.get,
param: {
"publishOnApp": true,
},
headers: null,
isFormData: false,
contentType: 'application/json',
isFullPath: false,
language: "th",
date: null,
file: null,
check: false,
)).thenAnswer((_) async => Right(response));
}
void makeBannerListResponseSuccessfull(dynamic data) async {
final Response response = Response(
requestOptions: RequestOptions(path: 'path'),
statusCode: 200,
data: data);
when(mockNetworkManager.request(
path: bannerUrl,
method: Method.post,
param: request.toMap(),
headers: null,
isFormData: false,
contentType: 'application/json',
isFullPath: false,
language: "th",
date: null,
file: null,
check: false,
)).thenAnswer((_) async => Right(response));
}
onCallSuccess(() {
test('should perform GET for get shelve list successfully', () async {
final json = jsonDecode(fixture("shelve_list_data.json"));
final List<ShelveModel> list =
List<ShelveModel>.from(json.map((e) => ShelveModel.fromJson(e)));
// arrange
await makeResponseSuccessfull(json);
// act
final rs = await dataSource.getList(publishOnApp: true);
// assert
expect(rs, list);
});
test('should perform POST for get banner list successfully', () async {
final json = jsonDecode(fixture("banner_list_data.json"));
final List<ShelveBannerListModel> list = List<ShelveBannerListModel>.from(
json.map((e) => ShelveBannerListModel.fromJson(e)));
// arrange
makeBannerListResponseSuccessfull(json);
// act
final rs = await dataSource.getBannerList(request: request);
// assert
expect(rs, list);
});
});
}
My NetworkManager class:
import 'dart:convert';
import 'dart:io';
import 'package:dartz/dartz.dart';
import 'package:dio/dio.dart';
import 'package:flutter_flavor/flutter_flavor.dart';
import 'package:injectable/injectable.dart';
import 'package:true_food/core/constant.dart';
import 'package:true_food/core/error/error.dart';
import 'package:true_food/core/error/exceptions.dart';
import 'package:true_food/core/local_storage.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:true_food/gen/locale_keys.g.dart';
import 'package:dio/adapter.dart';
#lazySingleton
class NetworkManager {
final dio = Dio();
Future<Either<ServerException, Response>> request({
required String path,
required Method method,
Map<String, dynamic>? param,
Map<String, dynamic>? headers,
bool isFormData = false,
String contentType = 'application/json',
bool isFullPath = false,
String language = 'vi',
// ignore: avoid_init_to_null
DateTime? date = null,
// ignore: avoid_init_to_null
FormData? file = null,
bool check = false,
}) async {
final String? _token = LocalStorage().getString(Constant.accessToken);
print('_token: $_token');
String domain = FlavorConfig.instance.variables["baseUrl"] ?? '';
String _finalPath = domain + path;
Map<String, dynamic> _finalParam = {};
if (param != null) {
print(param);
_finalParam.addAll(param);
}
try {
Map<String, dynamic>? _header =
_token != null ? {"Authorization": "Bearer " + _token} : null;
Response response = Response(requestOptions: RequestOptions(path: path));
Options optionsCommon = Options(
headers: _header,
sendTimeout: 30 * 1000,
receiveTimeout: 30 * 1000,
contentType: contentType,
);
//handle old printic with the request without content type
switch (method) {
case Method.get:
response = await dio.get(
_finalPath,
queryParameters: _finalParam,
options: optionsCommon,
cancelToken: null,
onReceiveProgress: null,
);
break;
case Method.post:
var data = isFormData ? file : _finalParam;
response = await dio.post(
_finalPath,
options: optionsCommon,
data: data,
cancelToken: null,
onReceiveProgress: null,
);
break;
case Method.put:
var data = isFormData ? file : _finalParam;
response = await dio.put(
_finalPath,
options: optionsCommon,
data: data,
cancelToken: null,
onReceiveProgress: null,
);
break;
case Method.delete:
var data = isFormData ? file : _finalParam;
response = await dio.delete(
_finalPath,
options: optionsCommon,
data: data,
cancelToken: null,
);
break;
}
print('==> DIO SUCCESS <$path> RESPONSE :\n'
'${response.data}');
// onSuccess(response.data, response.statusCode ?? 200);
return Right(response);
} on DioError catch (e) {
if (e.response != null) {
final Response rp = e.response!;
if (rp.statusCode == 502) {
// showToast("Server is maintaining, please login later".tr());
// UserManager.instance.logout();
// EasyLoading.dismiss();
}
print('~~> e: ${e.error}');
print('==> DIO FAILED <$path> RESPONSE :\n'
'${e.response?.data ?? ""}');
final data = rp.data;
try {
final json = jsonDecode(data);
return Left(ServerException(appError: AppError.fromJson(json)));
} on Exception {
return Left(ServerException(
appError: AppError(
status: 500,
title: LocaleKeys.something_went_wrong.tr(),
message: LocaleKeys.something_went_wrong.tr())));
}
} else {
return Left(ServerException(
appError: AppError(
status: 500,
title: LocaleKeys.something_went_wrong.tr(),
message: LocaleKeys.something_went_wrong.tr(),
),
));
}
} on SocketException {
return Left(ServerException(
appError: AppError(
status: 500,
title: LocaleKeys.something_went_wrong.tr(),
message: LocaleKeys.something_went_wrong.tr())));
}
}
}
enum Method { post, get, put, delete }
Pubspec:
Mockito version: "5.1.0"
Dio version "4.0.5"
MissingStubError: 'request'
No stub was found which matches the arguments of this method call:
request({path: api/shelves, method: Method.get, param: {publishOnApp: true}, headers: null, isFormData: false, contentType: application/json, isFullPath: false, language: vi, date: null, file: null, check: false})
Add a stub for this method using Mockito's 'when' API, or generate the MockNetworkManager mock with a MockSpec with 'returnNullOnMissingStub: true' (see https://pub.dev/documentation/mockito/latest/annotations/MockSpec-class.html).
I am using a helper class to make request to server for that I am using Dio.
I want to test the helper class
this is my helper class
import 'package:dio/dio.dart';
import '../error/exceptions.dart';
enum HttpMethod { GET, POST, PUT, DELETE }
abstract class ApiClient {
Future<Response> request(
HttpMethod method,
String path, {
Map<String, dynamic>? headers,
Map<String, dynamic>? queryParams,
dynamic body,
});
}
/// This class provides http calls using dio package
class ApiClientImpl implements ApiClient {
final Dio dio;
ApiClientImpl({required this.dio});
#override
Future<Response> request(
HttpMethod method,
String path, {
Map<String, dynamic>? headers,
Map<String, dynamic>? queryParams,
dynamic body,
}) async {
// we can add headers here which are common for every restapi call
// headers = {'content-type': 'application/json'};
try {
final _response = await dio.request(
path,
options: Options(
method: _getApiMethodString(method),
headers: headers,
),
queryParameters: queryParams,
data: body,
);
return _response;
} on DioError {
throw FetchDataException('Dio Error Occurred');
}
}
String _getApiMethodString(HttpMethod method) {
switch (method) {
case HttpMethod.GET:
return 'GET';
case HttpMethod.POST:
return 'POST';
case HttpMethod.PUT:
return 'PUT';
case HttpMethod.DELETE:
return 'DELETE';
}
}
}
The test I wrote for it is
#GenerateMocks([Dio])
void main() {
late MockDio dio;
late ApiClientImpl apiClient;
setUp(() {
dio = MockDio();
apiClient = ApiClientImpl(dio: dio);
});
group('ApiService class methods test', () {
test('Should return response when request to server is made', () async {
// arrange
var successMessage = {'message': 'Success'};
const baseUrl = 'https://example.com/';
final options = Options(method: 'GET', headers: null);
when(dio.request(baseUrl,
options: options, queryParameters: anyNamed('queryParameters')))
.thenAnswer((_) async => Response(
requestOptions: RequestOptions(path: baseUrl),
data: successMessage,
statusCode: 200));
// act
final response = await apiClient.request(HttpMethod.GET, baseUrl);
// assert
expect(response.data, successMessage);
});
});
}
I am getting an error
MissingStubError: 'request'
No stub was found which matches the arguments of this method call:
request('https://example.com/', {data: null, queryParameters: null, cancelToken: null, options: Instance of 'Options', onSendProgress: null, onReceiveProgress: null})
How Can I write a correct test for the helper class.
I am trying to write unit tests for my request with Dio but I keep getting this error:
type 'Null' is not a subtype of type 'BaseOptions'
I tried adding the base options on DioMock in a lot of different ways but the test remains the same.
How can I fix it?
Bellow are my Network class and the test class.
class NetworkService {
final Dio dio;
NetworkService(this.dio){
dio.options.baseUrl = "https://food2fork.ca/api/recipe/search";
dio.options.headers['Authorization'] = 'Token 9c8b06d329136da358c2d00e76946b0111ce2c48';
dio.interceptors.add(InterceptorsWrapper(
onRequest: (options, handler){
print('base ${options.baseUrl}');
print("PATH: ${options.path}");
return handler.next(options);
},
onResponse: (response, handler){
print("RESPONSE: ${response.statusCode} PATH: ${response.requestOptions.path}");
return handler.next(response);
},
onError: (DioError e, handler){
print("ERROR: ${e.response?.statusCode} => PATH: ${e.requestOptions.path}");
return handler.next(e);
}
));
}
Future<List<Recipe>> getRecipe() async {
var response = await dio.get('/?page=1&query=beef');
print("response ${response.data}");
if(response.statusCode == 200){
final List<Recipe> recipeList = [];
for(Map<String, dynamic> recipe in response.data['results']){
recipeList.add(Recipe.fromJson(recipe));
}
return recipeList;
} else {
throw Exception('sss');
}
// ONBOARDING
}
}
class DioMock extends Mock implements DioForNative {}
class RecipeMock extends Mock implements Recipe {}
main() {
final dio = DioMock();
final service = NetworkService(dio);
dio.options.baseUrl = "https://food2fork.ca/api/recipe/search";
dio.options.headers = { 'Content-type': 'application/json', 'Accept': 'application/json' };
test("should return Onboarding Model", () async {
final response = Response(
requestOptions: RequestOptions(
path: 'gfh',
baseUrl: "fgh"
),
data: RecipeMock()
);
when(dio.get(
"https://food2fork.ca/api/recipe/search"))
.thenAnswer((_) async => response);
final result = await service.getRecipe();
expect(result, isA<Recipe>());
});
}
You should use https://pub.dev/packages/http_mock_adapter package to help you mock your DIO requests
See its example https://github.com/lomsa-dev/http-mock-adapter/blob/main/example/main.dart :
void main() async {
late Dio dio;
late DioAdapter dioAdapter;
Response<dynamic> response;
group('Accounts', () {
const baseUrl = 'https://example.com';
const userCredentials = <String, dynamic>{
'email': 'test#example.com',
'password': 'password',
};
setUp(() {
dio = Dio(BaseOptions(baseUrl: baseUrl));
dioAdapter = DioAdapter(dio: dio);
});
test('signs up user', () async {
const route = '/signup';
dioAdapter.onPost(
route,
(server) => server.reply(201, null),
data: userCredentials,
);
// Returns a response with 201 Created success status response code.
response = await dio.post(route, data: userCredentials);
expect(response.statusCode, 201);
});
...
final dioError = DioError(
error: {'message': 'Some beautiful error!'},
requestOptions: RequestOptions(path: path),
response: Response(
statusCode: 500,
requestOptions: RequestOptions(path: path),
),
type: DioErrorType.response,
);
test("should return a DioError", () async {
dioAdapter.onGet(
path,
(server) {
server.throws(404, dioError );
});
final result = await service.getOnboardingAnswer("lastAnswerId");
expect(result, throwsA(isA<DioError>()));
});
}
});
I follow the below code, but it seems not to work:
var body = jsonEncode(<String, String>{
'uid': uid,
'limit': '10',
'offset': '2',
'action': 'feed',
});
final response = await http.post(
Uri.parse('http://abc.or/fb/selectPosts.php'),
body: body,
);
if (response.statusCode == 200) {
List<Post> posts = [];
// If the server did return a 200 OK response,
// then parse the JSON.
print((jsonDecode(response.body)));
return List<Post>.from(jsonDecode(response.body));
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to update album.');
}
My API looks like this: http:/abc.or/fb/post.php?uid=aaaa&limit=10&offset=2&action=feed
try this.
import 'package:http/http.dart';
...
static const urlPrefix = 'https://jsonplaceholder.typicode.com';
...
Future<void> makePostRequest() async {
final url = Uri.parse('$urlPrefix/posts');
final headers = {"Content-type": "application/json"};
final json = '{"title": "Hello", "body": "body text", "userId": 1}';
final response = await post(url, headers: headers, body: json);
print('Status code: ${response.statusCode}');
print('Body: ${response.body}');
}
Those are query fields not request body fields.
They are passed in the link or as queryparematers in a Uri
final response = await http.get(
Uri(
path: <your url without the queries(http://abc)>,
query: <Your queries as they are in the string (uid=aaaa&limit=10&offset=2&action=feed), you can use string interpolation to fix the values in or better still use queryparematers, not both>
queryParameters : <String, dynamic>{ 'uid': uid, 'limit': 10, 'offset': 2, 'action': feed },)
);
I use a get method which should be the standard for such url. Do confirm from whoever wrote the api if it is a uses a get or post method.
I have this error;
Could there be a problem with the token.It says Uri invalid token, but I login beforehand, why can't I read it? Headers I add token like this..But it isnt work how solve it ? What could I have done wrong?
And So map, ifwhere, where or other things dont work..
I'm new to this platform, I may have asked something very simple, sorry for that.
Thank you for all ....
import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:flutter_knowin_app/core/data/response.dart';
import 'package:flutter_knowin_app/core/util/constants.dart';
import 'package:flutter_knowin_app/features/promotions/domain/entities/check.dart';
import 'package:flutter_knowin_app/features/promotions/domain/entities/spin.dart';
import 'package:flutter_knowin_app/features/promotions/domain/repositories/spin_repository.dart';
import 'package:flutter_knowin_app/features/promotions/domain/usecases/check_regular.dart';
import 'package:flutter_knowin_app/features/promotions/domain/usecases/check_vip.dart';
import 'package:flutter_knowin_app/injection_container.dart';
part 'spin_event.dart';
part 'spin_state.dart';
enum SpinPageState {
regular,
vip,
}
class SpinBloc extends Bloc<SpinEvent, SpinState> {
final SpinRepository spinRepository = sl<SpinRepository>();
SpinPageState spinPageState;
bool stateVip;
bool spinState = false;
String winThing;
int winResult;
int gamePlayCountVip;
int gamePlayCountRegular;
checksRegular ChecksRegular;
checksVip ChecksVip;
SpinBloc({
#required checksRegular ChecksRegular,
#required checksVip ChecksVip,
})
: assert(checksRegular != null),
assert(checksVip != null),
ChecksRegular = ChecksRegular,
ChecksVip = ChecksVip,
super(SpinState.initial());
#override
Stream<SpinState> mapEventToState(SpinEvent event,) async* {
final SpinRepository spinRepository = sl<SpinRepository>();
SpinState.initial();
if (event is SpinLoadingEvent) {
Response updateResponse;
yield SpinLoadingState();
final checkRegularOrFailure = await ChecksRegular(
checksRegularParams());
final checkVipOrFailure = await ChecksVip(
checksVipParams());
checkRegularOrFailure.fold((failure) {
updateResponse = Response(
status: false,
message: UNEXPECTED_FAILURE_MESSAGE,
statusCode: "FAIL CHECK REGULAR",
);
}, (response) {
spinState = true;
spinPageState = SpinPageState.regular;
response.toList().where((e){
print("PEOPLE COUNT= ${ e.gamePlayed}");
});
});
checkVipOrFailure.fold((failure) {
updateResponse = Response(
status: false,
message: UNEXPECTED_FAILURE_MESSAGE,
statusCode: "FAIL CHECK VIP",
);
}, (response) {
spinState = true;
spinPageState = SpinPageState.vip;
});
yield SpinLoadingState();
}
if (event is SpinStartEvent) {
}
}
}
RemoteCode;
class PromotionRemoteDataSourceImpl implements PromotionRemoteDataSource {
String token;
final http.Client client;
PromotionRemoteDataSourceImpl({this.client});
Map<String, String> get defaultHeaders =>
{
'Accept': 'application/json',
'Authorization': 'Bearer $token',
"Content-Type": "application/json"
};
Map<String, String> get defaultQueryParams => {
"lang": Platform.localeName.split('_')[0],
};
#override
Future<List<Check>> checksRegular() async {
Uri uri = Uri.https(
API_URL,
'/promotions/check/regular',
defaultQueryParams,
);
print("URİ: "+ uri.toString());
final response = await client.get(uri, headers: defaultHeaders);
final body= json.decode(response.body);
I solved the error like this;
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
sl<PromotionRemoteDataSource>().token = userState.token;//!!!
});
}
I think the problem is here
response.toList().where((e){
print("PEOPLE COUNT= ${ e.gamePlayed}");
});
The reason why is as the error message stated. The response variable is null, and you're trying to convert null to a list and Dart didn't like that. Implement some way to deal with the scenario where response is null, e.g. have an if statement there, and that should hopefully solve your problem