Giter Club home page Giter Club logo

Comments (26)

theiskaa avatar theiskaa commented on May 27, 2024 10

Hi, @Alvarocda and @funwithflutter. First of all thanks for contributing.

We were solved the problem by just adding content-length into headers. However, if you are putting a data with request
then you should add a concrete content-length into your headers of dios' map/payload.

So we solved the problem by adding Headers.contentLengthHeader: Matchers.integer into headers. This makes it so that any integer put into content-length value will be mocked by the package, meaning that you won't have to specify a concrete content-length value for different data.

Full headers code:

 final headers = <String, dynamic>{
      'Authorization': 'Bearer authToken',
      Headers.contentTypeHeader: Headers.jsonContentType,
      Headers.contentLengthHeader: Matchers.integer
    };

@Alvarocda we guess this solution will be solved your issue, If something went wrong please comment under this issue, we'll try solving and finding the best solution for that. Thanks again!

from http-mock-adapter.

funwithflutter avatar funwithflutter commented on May 27, 2024 8

@GiorgiBeriashvili you're a legend. Should have realised that. I tested it with the sample that I gave and in my code base, and can confirm that it works.

I definitely think examples of using headers should be added to the docs, or to the samples.

Also note that there is a typo in the ReadMe describing the basic usage. Below is taken from the readme:

dioAdapter
      ..onGet(
        path,
        (request) => request.reply(200, {'message': 'Successfully mocked GET!'}),
      )
      ..onGet(
        path,
        (request) => request.reply(200, {'message': 'Successfully mocked POST!'}),
      );

..onGet is used for both the GET and POST mock.

Thanks again!

from http-mock-adapter.

GiorgiBeriashvili avatar GiorgiBeriashvili commented on May 27, 2024 5

@GiorgiBeriashvili My code was exactly like yours except it was like final response = await dio.post('/example'); And this was causing the null and {} comparison.

test('it uses correct headers for post requests', () async {
      dioAdapter.onPost(testPath, headers: {
        'accept': 'application/json',
        'content-type': 'application/json',
        'X-TENANT-TOKEN': null,
        'content-length': 2
      }).reply(200, {'data': 'ok'});

      ResponseModel response = await apiHandler.post(testPath);
      expect(response.data, equals(['ok']));
    });

(Here dioAdapter is the adapter, apiHandler is a class we use for HTTP calls which uses Dio, testPath is just a string)

Note: This was with an earlier version of the library, before the API change.

I would not exclude the possibility of bug regarding previous versions of http_mock_adapter, and it also seems off that you match onPost with predefined headers but you don't include them in the POST request. Maybe that could be the source of the bug, but I am unsure.

However, if it is of any help, I tried to rewrite your example on the latest version with no problems as I tested:

import 'package:dio/dio.dart';
import 'package:http_mock_adapter/http_mock_adapter.dart';
import 'package:test/test.dart';

void main() {
  test('Matching a POST request with an empty map', () async {
    final dio = Dio();
    final dioAdapter = DioAdapter();

    const headers = <String, dynamic>{
      'accept': 'application/json',
      'content-type': 'application/json',
      'X-TENANT-TOKEN': null,
      'content-length': 2
    };

    const data = {'data': 'ok'};

    dio.httpClientAdapter = dioAdapter;

    dioAdapter.onPost(
      '/example',
      (request) => request.reply(200, data),
      headers: headers,
    );

    final response = await dio.post(
      '/example',
      options: Options(headers: headers),
    );

    expect(data, response.data);
  });
}

Hopefully this could be of some use. I am unsure if the issue is due to bugs in previous versions or the fact that you don't include headers in post (in the current version, there would be an error regarding header mismatch), but I haven't personally ever experienced issue regarding sortedData method and I hope that it is not the source of the issue as tracking the reason would not be as trivial.

Is there any other way I can be of assistance? I suggest and encourage you to migrate to the newest version, it should be worth it as it generally seems more stable (latest issues are mostly due to lack of documentation or extra features, not due to some bug).

from http-mock-adapter.

canvural avatar canvural commented on May 27, 2024 4

I had the similar problem. I did some digging and found that the issue was sortedData method. It sometimes returned null and sometimes {}

So it was trying to compare https://example.com/POST/{}/{}/{content-type: application/json, accept: application/json, content-length: 2} with https://example.com/POST/null/{}/{content-type: application/json, accept: application/json, content-length: 2} and fail. (look at the part after POST/)

So my solution was to add empty data to my dioAdapter.onPost call.

Hope it helps someone, until this is fixed.

from http-mock-adapter.

funwithflutter avatar funwithflutter commented on May 27, 2024 3

@Alvarocda this is what I experience as well. If both data and headers are provided then it fails.

from http-mock-adapter.

Alvarocda avatar Alvarocda commented on May 27, 2024 2

Hello!
Thank you for the detailed explanation! It makes it noticeably easy to debug the issue.

Fix

A quick fix is to accompany one more key and value pair to the headers map, namely content-type: application/json; charset=utf-8:

  final headers = <String, String>{
    'Authorization': 'Bearer authToken',
    Headers.contentTypeHeader: Headers.jsonContentType,
  };

Output

{message: Successfully mocked GET!}
✓ on get with headers
{message: Successfully mocked POST!}
✓ on post with headers
{message: Successfully mocked DELETE!}
✓ on delete with headers
{message: Successfully mocked PUT!}
✓ on put with headers

Please let us know if this fixes the issue and if there is anything else we can do to help!

Explanation

As far as I know and understand, http_mock_adapter by default includes Headers.contentTypeHeader: Headers.jsonContentType key and value pair to every request, which makes it easier for the users not to include it for every request by hand, while also gluing nicely with Dio as Dio is seemingly tightly integrated with JSON.
As you declare custom headers, Dio's get does not require JSON encoding, probably because it only retrieves the data, but other methods such as post, delete, and put in this case might have an accompanying data and JSON encoding becomes prevalent in that case. That's why get works but other methods fail to match. In order to fix the issue, you must include content-type: application/json; charset=utf-8 to the headers map because it will overwrite the package's underlying default values.
I could be wrong about the underlying mechanism and technical details, but from what I know, http_mock_adapter largely uses and relies on JSON data because both users and Dio expect data to be encoded in JSON format.
The aforementioned code will fix the issue, but of course, there could be a better way to deal with the problem, both on the user's end and also in the package itself.

Same problem here, i tryed this, but still not working

Could you provide context and code?

Sorry for the delay.
example 2

The image above is my test method, i create an dioAdapter, pass the url i want to mock and the reply.
Tryied with headers and without headers, when it runs it gives me "Could not find mocked route matching request for.."

post method
The image above is my post method

this is the stacktrace of the error

#0      History.responseBody.<anonymous closure> (package:http_mock_adapter/src/history.dart:32:11)
#1      DioAdapter.fetch (package:http_mock_adapter/src/adapters/dio_adapter.dart:47:48)
#2      DioMixin._dispatchRequest (package:dio/src/dio_mixin.dart:632:46)
<asynchronous suspension>
#3      StackZoneSpecification._registerUnaryCallback.<anonymous closure> (package:stack_trace/src/stack_zone_specification.dart)
<asynchronous suspension>

i noticed this. when it calls my post method, the url is correct, as you can see in the image bellow
normal url

But on the exception, it shows a different url, as you can see in the image bellow
strange url

from http-mock-adapter.

funwithflutter avatar funwithflutter commented on May 27, 2024 2

@theiskaa Thanks a ton! For me this issue can be closed.

from http-mock-adapter.

Alvarocda avatar Alvarocda commented on May 27, 2024 2

Hi, @theiskaa the POST is now working but now, all requests are returning the POST mocked reply
I have this 3 endpoints, when i call any GET endpoint, it returns the reply of the POST endpoint

    final Map<String, dynamic> headers = <String, dynamic>{
      Headers.contentTypeHeader: Headers.jsonContentType,
      Headers.contentLengthHeader: Matchers.integer
    };

    Map<String, dynamic> jsonContent = <String, dynamic>{
      'chaveAcesso': 'myAccessKey',
      'chaveSecreta': 'mySecretKey',
    };
    String jsonString = json.encode(jsonContent);

    DioAdapter dioAdapter = DioAdapter();

    dioAdapter
      ..onGet(
        'https://my.api/v1/sosmulher/deferimento/codigo/100004',
        (RequestHandler<dynamic> request) =>
            request.reply(200, StaticJsons.informacaoDeferimentoCodigoExpirado),
      )
      ..onGet(
        'https://my.api/v1/sosmulher/detalhamento/codigo/100004',
        (RequestHandler<dynamic> request) => request.reply(
            200, StaticJsons.informacaoDetalhamentoCodigoExpirado),
      )
      ..onPost(
        'https://my.api/v1/login',
        (RequestHandler<dynamic> request) =>
            request.reply(200, StaticJsons.jsonLogin),
        headers: headers,
        data: jsonString,
      );
    await ConnectionUtils().initialize(adapter: dioAdapter);

from http-mock-adapter.

Alvarocda avatar Alvarocda commented on May 27, 2024 2

I discovered this.
When i run this method from my ConnectionUtils class the bug happens, if i dont run this method, all GET requests works fine

 ///
  ///
  ///
  Future<void> getAccessToken() async {
    if (!_dio.options.headers.containsKey('authorization')) {
      Map<String, dynamic> jsonContent = <String, dynamic>{
        'chaveAcesso': 'myAccessKey',
        'chaveSecreta': 'mySecretKey',
      };

      Response<dynamic> resposta = await post(
          'https://my.api/login',
          jsonContent);

      String accessToken = resposta.data['accessToken'];

      _dio.options.headers.addAll(
        <String, dynamic>{'authorization': 'Bearer $accessToken'},
      );
    }
  }

from http-mock-adapter.

Alvarocda avatar Alvarocda commented on May 27, 2024 2

I found the problem
The following code can reproduce my error

  test('mocks the data with onRoute', () async {
    DioAdapter dioAdapter = DioAdapter();
    final Map<String, dynamic> headers = <String, dynamic>{
      Headers.contentTypeHeader: Headers.jsonContentType,
      Headers.contentLengthHeader: Matchers.integer
    };

    Map<String, dynamic> jsonContent = <String, dynamic>{
      'chaveAcesso': 'myAccessKey',
      'chaveSecreta': 'mySecretKey',
    };
    dioAdapter
      ..onGet(
        'https://my.api/v1/sosmulher/deferimento/codigo/100004',
        (request) => request.reply(
            200, StaticJsons.informacaoDeferimentoCodigoIndeferido),
      )
      ..onGet(
        'https://my.api/v1/sosmulher/detalhamento/codigo/100004',
        (request) => request.reply(
            200, StaticJsons.informacaoDetalhamentoCodigoIndeferido),
      )
      ..onPost(
        'https://my.api/v1/login',
        (request) => request.reply(200, StaticJsons.jsonLogin),
        headers: headers,
        data: json.encode(jsonContent),
      );

    Dio dio = Dio();
    dio.httpClientAdapter = dioAdapter;

    final getLogin = await dio.post<dynamic>(
      "https://my.api/v1/login",
      data: json.encode(jsonContent),
    );
 
    String accessToken = getLogin.data['accessToken'];

    dio.options.headers.addAll(
      <String, dynamic>{'authorization': 'Bearer $accessToken'},
    );

    final getDeferimento = await dio.get<dynamic>(
      "https://my.api/v1/sosmulher/deferimento/codigo/100004",
    );

    final getGetalhamento = await dio.get<dynamic>(
      "https://my.api/v1/sosmulher/detalhamento/codigo/100004",
    );

    expect(
        getDeferimento.data, StaticJsons.informacaoDeferimentoCodigoIndeferido);
    expect(getGetalhamento.data,
        StaticJsons.informacaoDetalhamentoCodigoIndeferido);
    expect(getLogin.data, StaticJsons.jsonLogin);
  });

This is where the problem happens, if i comment this piece of code, everything works fine

    dio.options.headers.addAll(
      <String, dynamic>{'authorization': 'Bearer $accessToken'},
    );

This makes dio add the authorization header in all requests automatically

from http-mock-adapter.

GiorgiBeriashvili avatar GiorgiBeriashvili commented on May 27, 2024 1

Hello!

Thank you for the detailed explanation! It makes it noticeably easy to debug the issue.

Fix

A quick fix is to accompany one more key and value pair to the headers map, namely content-type: application/json; charset=utf-8:

  final headers = <String, String>{
    'Authorization': 'Bearer authToken',
    Headers.contentTypeHeader: Headers.jsonContentType,
  };

Output

{message: Successfully mocked GET!}
✓ on get with headers
{message: Successfully mocked POST!}
✓ on post with headers
{message: Successfully mocked DELETE!}
✓ on delete with headers
{message: Successfully mocked PUT!}
✓ on put with headers

Please let us know if this fixes the issue and if there is anything else we can do to help!

Explanation

As far as I know and understand, http_mock_adapter by default includes Headers.contentTypeHeader: Headers.jsonContentType key and value pair to every request, which makes it easier for the users not to include it for every request by hand, while also gluing nicely with Dio as Dio is seemingly tightly integrated with JSON.

As you declare custom headers, Dio's get does not require JSON encoding, probably because it only retrieves the data, but other methods such as post, delete, and put in this case might have an accompanying data and JSON encoding becomes prevalent in that case. That's why get works but other methods fail to match. In order to fix the issue, you must include content-type: application/json; charset=utf-8 to the headers map because it will overwrite the package's underlying default values.

I could be wrong about the underlying mechanism and technical details, but from what I know, http_mock_adapter largely uses and relies on JSON data because both users and Dio expect data to be encoded in JSON format.

The aforementioned code will fix the issue, but of course, there could be a better way to deal with the problem, both on the user's end and also in the package itself.

from http-mock-adapter.

Alvarocda avatar Alvarocda commented on May 27, 2024 1

Hello!

Thank you for the detailed explanation! It makes it noticeably easy to debug the issue.

Fix

A quick fix is to accompany one more key and value pair to the headers map, namely content-type: application/json; charset=utf-8:

  final headers = <String, String>{
    'Authorization': 'Bearer authToken',
    Headers.contentTypeHeader: Headers.jsonContentType,
  };

Output

{message: Successfully mocked GET!}
✓ on get with headers
{message: Successfully mocked POST!}
✓ on post with headers
{message: Successfully mocked DELETE!}
✓ on delete with headers
{message: Successfully mocked PUT!}
✓ on put with headers

Please let us know if this fixes the issue and if there is anything else we can do to help!

Explanation

As far as I know and understand, http_mock_adapter by default includes Headers.contentTypeHeader: Headers.jsonContentType key and value pair to every request, which makes it easier for the users not to include it for every request by hand, while also gluing nicely with Dio as Dio is seemingly tightly integrated with JSON.

As you declare custom headers, Dio's get does not require JSON encoding, probably because it only retrieves the data, but other methods such as post, delete, and put in this case might have an accompanying data and JSON encoding becomes prevalent in that case. That's why get works but other methods fail to match. In order to fix the issue, you must include content-type: application/json; charset=utf-8 to the headers map because it will overwrite the package's underlying default values.

I could be wrong about the underlying mechanism and technical details, but from what I know, http_mock_adapter largely uses and relies on JSON data because both users and Dio expect data to be encoded in JSON format.

The aforementioned code will fix the issue, but of course, there could be a better way to deal with the problem, both on the user's end and also in the package itself.

Same problem here, i tryed this, but still not working

from http-mock-adapter.

GiorgiBeriashvili avatar GiorgiBeriashvili commented on May 27, 2024 1

@funwithflutter I am glad the issue is resolved for you. Thank you very much!

Agreed regarding the documentation, we will definitely improve it. The example in README.md is fixed on develop and will be merged on main soon!

I will let the issue be open for a bit or until @Alvarocda replies regarding the problem he mentioned.

from http-mock-adapter.

funwithflutter avatar funwithflutter commented on May 27, 2024 1

Back with a different, but similar problem 😄.

I get the 'Could not find mocked route...' as soon as I add both a data and header. Below test will fail:

test('mocks the data with onRoute', () async {
      final data = <String, dynamic>{'message': 'Successfully mocked PATCH!'};

      final payload = jsonEncode({
        'payload': {'data': 'Test data!'},
      });

      final headers = <String, String>{
        'Authorization': 'Bearer authToken',
        Headers.contentTypeHeader: Headers.jsonContentType,
      };

      dioAdapter.onRoute(
        path,
        (request) => request.reply(200, data),
        request: Request(
          method: RequestMethods.post,
          data: payload,
          headers: headers,
        ),
      );

      final patchResponse = await dio.post<dynamic>(
        path,
        data: payload,
        options: Options(headers: headers),
      );

      expect(patchResponse.data, data);
    });

Remove the data parameter and the test passes. Remove the headers and the test passes. But having both gives the issue.

I modded the above from the examples. Same happens when using dioAdapter.onPost (I didn't test DELETE and PUT).

from http-mock-adapter.

theiskaa avatar theiskaa commented on May 27, 2024 1

@Alvarocda I tried what you said, but I could not found any problem there.
Probably you mean like this act right? if you are, it works without any kind of problem.

 test('mocks the data with onRoute', () async {
    dioAdapter
      ..onGet(
        'https://my.api/v1/sosmulher/deferimento/codigo/100004',
        (request) => request.reply(200, data),
      )
      ..onGet(
        'https://my.api/v1/sosmulher/detalhamento/codigo/100004',
        (request) => request.reply(200, data),
      )
      ..onPost(
        'https://my.api/v1/login',
        (request) => request.reply(200, data),
        headers: headers,
        data: jsonString,
      );

    final getDeferimento = await dio.get<dynamic>(
      "https://my.api/v1/sosmulher/deferimento/codigo/100004",
    );

    final getGetalhamento = await dio.get<dynamic>(
      "https://my.api/v1/sosmulher/detalhamento/codigo/100004",
    );

    final getLogin = await dio.post<dynamic>(
      "https://my.api/v1/login",
      data: jsonString,
    );

    expect(getDeferimento.data, data);
    expect(getGetalhamento.data, data);
    expect(getLogin.data, data);
  });

from http-mock-adapter.

Alvarocda avatar Alvarocda commented on May 27, 2024 1

I'll debug a little more to try to find out what's going on, my code is exactly the same as the one you posted, but it keeps responding to all requests, the POST response

from http-mock-adapter.

Alvarocda avatar Alvarocda commented on May 27, 2024 1

This is my test method

void main(){
  GetIt locator = GetIt.instance;

  ///
  ///
  ///
  setUp(() {
    locator.reset();
    locator.registerLazySingleton<CodigoRepository>(
        () => MockedCodigoRepository());
    locator.registerLazySingleton<ConsumerCodigo>(() => ConsumerCodigo());
  });

  testWidgets('Adiciona um código que não existe', (WidgetTester tester) async {
    DioAdapter dioAdapter = DioAdapter();
    final Map<String, dynamic> headers = <String, dynamic>{
      Headers.contentTypeHeader: Headers.jsonContentType,
      Headers.contentLengthHeader: Matchers.integer
    };

    Map<String, dynamic> jsonContent = <String, dynamic>{
      'chaveAcesso': 'myAccessKey',
      'chaveSecreta': 'mySecretKey',
    };

    dioAdapter
      ..onGet(
        'https://my.api/v1/sosmulher/deferimento/codigo/100004',
        (request) =>
            request.reply(200, StaticJsons.informacaoDeferimentoCodigoIndeferido),
      )
      ..onGet(
        'https://my.api/v1/sosmulher/detalhamento/codigo/100004',
        (request) =>
            request.reply(200, StaticJsons.informacaoDetalhamentoCodigoIndeferido),
      )
      ..onPost(
        'https://my.api/v1/login',
        (request) => request.reply(200, StaticJsons.jsonLogin),
        headers: headers,
        data: json.encode(jsonContent),
      );
    await ConnectionUtils().initialize(adapter: dioAdapter);
    await createWidget(tester, CodigoAdicionaScreen());
    await tester.enterText(find.byType(StringField), '100004');
    await tester.tap(find.byType(BotaoFormularios));

    await tester.pumpAndSettle();

    expect(find.byIcon(Icons.cancel_sharp), findsOneWidget);
    expect(
        find.text(
            'O código inserido não existe. Verifique se você digitou corretamente o código.'),
        findsOneWidget);
    await tester.pumpAndSettle(Duration(seconds: 7));
  });
}

This is my StaticJsons class, where i store all responses i want to test

  ///
  ///
  ///
  static Map<String, dynamic> get informacaoDeferimentoCodigoIndeferido {
    return <String, dynamic>{
      'informacao': 'deferimento',
      'codigo': 'indeferido'
    };
  }

  ///
  ///
  ///
  static Map<String, dynamic> get informacaoDetalhamentoCodigoIndeferido {
    return <String, dynamic>{
      'informacao': 'detalhamento',
      'codigo': 'indeferido'
    };
  }

  ///
  ///
  ///
  static Map<String, dynamic> get jsonLogin {
    return <String, dynamic>{
      'json': 'login',
      'accessToken': 'abcdef',
    };
  }

This the class that i use to connect to my api, its a singleton

///
///
///
class ConnectionUtils {
  static final ConnectionUtils _singleton = ConnectionUtils._internal();
  Dio _dio;

  ///
  ///
  ///
  factory ConnectionUtils() {
    return _singleton;
  }

  ///
  ///
  ///
  Future<void> initialize({HttpClientAdapter adapter}) async {
    _dio = Dio();
    if (adapter != null) {
      _dio.httpClientAdapter = adapter;
    }
  }
}

  ///
  ///
  ///
  Future<void> getAccessToken() async {
    if (!_dio.options.headers.containsKey('authorization')) {
      Map<String, dynamic> jsonContent = <String, dynamic>{
        'chaveAcesso': 'myAccessKey',
        'chaveSecreta': 'mySecretKey',
      };

      Response<dynamic> resposta = await post(
          'https://my.api/login',
          jsonContent);

      String accessToken = resposta.data['accessToken'];

      _dio.options.headers.addAll(
        <String, dynamic>{'authorization': 'Bearer $accessToken'},
      );
    }
  }

  ///
  ///
  ///
  Future<Response<dynamic>> get(
    String url, {
    Map<String, dynamic> queryParameters,
    Map<String, dynamic> headers,
  }) async {
    Response<dynamic> response = await _dio.get<dynamic>(
      url,
      queryParameters: queryParameters,
      options: Options(headers: headers),
    );

    return response;
  }

  ///
  ///
  ///
  Future<Response<dynamic>> post(
    String url,
    Object objeto, {
    Map<String, dynamic> headers,
  }) async {
    String conteudoJson;
    if (objeto != null) {
      conteudoJson = json.encode(objeto);
    }

    Response<dynamic> response = await _dio.post<dynamic>(
      url,
      data: conteudoJson,
      options: Options(headers: headers),
    );
    return response;
  }

The first thing my test do, is send a POST request on the login endpoint, and this is working fine, the response is correct
post

After sending login post request, it sends a GET request in a different endpoint, but, as you can see in the image bellow, it give me the same response as POST
first get

After the first GET, i need to do another GET request, and yet, it stills give me POST response, as you can see in the image bellow
second get

from http-mock-adapter.

GiorgiBeriashvili avatar GiorgiBeriashvili commented on May 27, 2024 1

@Alvarocda I reviewed your latest example and I got it working by adding two lines, but before I refer to code, I would like to analyze your example and why it failed based on how I infer your intention to test the example you wrote.

Correct me if I am wrong, but you are trying to send a POST request to an endpoint, obtain accessToken, and then set the token in the headers parameter of Dio's options in order to accompany the following two GET requests with an access token, which is relevant to what you are testing and is generally a popular/useful approach.

However, I am unsure if you are awake of http_mock_adapter's intrinsic details, but once you mock a request, it cannot be updated on the fly, you can only overwrite it. In this case, you mocked two GET requests but you did not mock them in the way that would signify that the mocked requests would accept headers containing authorization data, or anything at all. Due to this reason, once you set headers after you got access token from the POST request's result, the subsequent GET requests did not match the mocked requests because of header mismatch, which is visible in the error:

DioError [DioErrorType.other]: Assertion failed: "Could not find mocked route matching request for https://my.api/v1/sosmulher/detalhamento/codigo/100004/GET/null/{}/{authorization: Bearer TOKEN}"

In order to fix the issue, you either have to mock the GET requests AFTER you get hold of the access token (this is the variant when you have to hardcode the authorization header value), or alternatively, and perhaps even better, you simply add the following dynamic matchers to the onGet request handler methods:

      // -- snip --
      ..onGet(
        'https://my.api/v1/sosmulher/deferimento/codigo/100004',
        (request) => request.reply(
          200,
          {'key': 'value1'},
        ),
        headers: {'authorization': Matchers.string},
      )
      ..onGet(
        'https://my.api/v1/sosmulher/detalhamento/codigo/100004',
        (request) => request.reply(
          200,
          {'key': 'value2'},
        ),
        headers: {'authorization': Matchers.string},
      )
      // -- snip --

The headers: {'authorization': Matchers.string}, argument will ensure that any String value you input to the accompanying headers that only contains authorization header, will indeed be matched as defined. The tests will work afterwards.

As far as I am aware, the package is at no fault here, it's more akin human error, which is a better outcome if I were to be honest.

What do you think? Maybe we could improve documentation and provide clearer examples, but do you think that any changes regarding the intrinsic mechanisms of the package are needed?

Thank you for the detailed examples, on my part I would think that the issue should be fixed for you, but if I am wrong, please let me know!

from http-mock-adapter.

canvural avatar canvural commented on May 27, 2024 1

@GiorgiBeriashvili My code was exactly like yours except it was like final response = await dio.post('/example'); And this was causing the null and {} comparison.

test('it uses correct headers for post requests', () async {
      dioAdapter.onPost(testPath, headers: {
        'accept': 'application/json',
        'content-type': 'application/json',
        'X-TENANT-TOKEN': null,
        'content-length': 2
      }).reply(200, {'data': 'ok'});

      ResponseModel response = await apiHandler.post(testPath);
      expect(response.data, equals(['ok']));
    });

(Here dioAdapter is the adapter, apiHandler is a class we use for HTTP calls which uses Dio, testPath is just a string)

Note: This was with an earlier version of the library, before the API change.

from http-mock-adapter.

canvural avatar canvural commented on May 27, 2024 1

Yes, we are already using the latest version now. And it's working with my changes I wrote earlier. Thank you for the answers 👍🏽

from http-mock-adapter.

Bipinoli avatar Bipinoli commented on May 27, 2024 1

For me it worked when I put anyMather in data with Matchers.any
eg:

final headers = <String, dynamic>{
        'Authorization': 'Bearer authToken',
        Headers.contentTypeHeader: Headers.jsonContentType,
        Headers.contentLengthHeader: Matchers.integer
      };

dioAdapter.onPost('auth/register', (request) {
        return request.reply(200, {});
      }, headers: headers, data: Matchers.any);

from http-mock-adapter.

Alvarocda avatar Alvarocda commented on May 27, 2024 1
headers: {'authorization': Matchers.string}

Worked here, thanks!!

from http-mock-adapter.

GiorgiBeriashvili avatar GiorgiBeriashvili commented on May 27, 2024

Hello!

Thank you for the detailed explanation! It makes it noticeably easy to debug the issue.

Fix

A quick fix is to accompany one more key and value pair to the headers map, namely content-type: application/json; charset=utf-8:

  final headers = <String, String>{
    'Authorization': 'Bearer authToken',
    Headers.contentTypeHeader: Headers.jsonContentType,
  };

Output

{message: Successfully mocked GET!}
✓ on get with headers
{message: Successfully mocked POST!}
✓ on post with headers
{message: Successfully mocked DELETE!}
✓ on delete with headers
{message: Successfully mocked PUT!}
✓ on put with headers

Please let us know if this fixes the issue and if there is anything else we can do to help!

Explanation

As far as I know and understand, http_mock_adapter by default includes Headers.contentTypeHeader: Headers.jsonContentType key and value pair to every request, which makes it easier for the users not to include it for every request by hand, while also gluing nicely with Dio as Dio is seemingly tightly integrated with JSON.

As you declare custom headers, Dio's get does not require JSON encoding, probably because it only retrieves the data, but other methods such as post, delete, and put in this case might have an accompanying data and JSON encoding becomes prevalent in that case. That's why get works but other methods fail to match. In order to fix the issue, you must include content-type: application/json; charset=utf-8 to the headers map because it will overwrite the package's underlying default values.

I could be wrong about the underlying mechanism and technical details, but from what I know, http_mock_adapter largely uses and relies on JSON data because both users and Dio expect data to be encoded in JSON format.

The aforementioned code will fix the issue, but of course, there could be a better way to deal with the problem, both on the user's end and also in the package itself.

Same problem here, i tryed this, but still not working

Could you provide context and code?

from http-mock-adapter.

GiorgiBeriashvili avatar GiorgiBeriashvili commented on May 27, 2024

I had the similar problem. I did some digging and found that the issue was sortedData method. It sometimes returned null and sometimes {}

So it was trying to compare https://example.com/POST/{}/{}/{content-type: application/json, accept: application/json, content-length: 2} with https://example.com/POST/null/{}/{content-type: application/json, accept: application/json, content-length: 2} and fail. (look at the part after POST/)

So my solution was to add empty data to my dioAdapter.onPost call.

Hope it helps someone, until this is fixed.

Could you please provide an example? I will try to infer the example based on what I think might be the case.

I think this is intended behavior, since {} does not equal null. Were you trying to send a POST request and accompanied an empty map as data? In this case, the test would fail, as it would be unable to match {} with null. Bare equality fail example:

  expect(null, {});
Expected: {}
  Actual: <null>
   Which: expected a map

And I am guessing that you did something similar to this, which would result in an error written below the code snippet:

  test('Matching a POST request with an empty map', () async {
    final dio = Dio();
    final dioAdapter = DioAdapter();

    dio.httpClientAdapter = dioAdapter;

    dioAdapter.onPost(
      '/example',
      (request) => request.reply(200, 'Success!'),
    );

    final response = await dio.post('/example', data: {});

    expect('Success!', response.data);
  });
DioError [DioErrorType.other]: Assertion failed: "Could not find mocked route matching request for /example/POST/{}/{}/{content-type: application/json; charset=utf-8, content-length: 2}"

If you add data: {}, argument, then the test finishes successfully:

    // -- snip --
    dioAdapter.onPost(
      '/example',
      (request) => request.reply(200, 'Success!'),
      data: {},
    );
    // -- snip --
✓ Matching a POST request with an empty map

@canvural Thank you for bringing the issue to our attention. Please let me know if the issue lies in other cases, or if what I wrote above makes sense and can be considered as a non-hacky solution to the problem.

from http-mock-adapter.

GiorgiBeriashvili avatar GiorgiBeriashvili commented on May 27, 2024

Yes, we are already using the latest version now. And it's working with my changes I wrote earlier. Thank you for the answers 👍🏽

I'm glad! Thank you for reaching out and helping us improve the package!

I will await @Alvarocda for confirmation regarding the last remaining case's solution before I close the issue.

from http-mock-adapter.

GiorgiBeriashvili avatar GiorgiBeriashvili commented on May 27, 2024

As everything regarding this issue seems to be resolved, I will close it.

from http-mock-adapter.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.