setupResponse function

MockHttpResponse setupResponse({
  1. Map<String, List<String>>? headers,
  2. List<Cookie>? cookies,
  3. BytesBuilder? body,
})

Sets up a mock HTTP response with the given headers and body.

This function creates a MockHttpResponse instance and configures it with the provided headers and body. It sets up the necessary mocks for the response's status code, headers, and body handling methods.

The returned MockHttpResponse instance can be used in tests to simulate an HTTP response.

Parameters:

  • headers: An optional map of headers to set on the response.
  • body: An optional BytesBuilder to capture the response body.

Returns: The configured MockHttpResponse instance.

Implementation

MockHttpResponse setupResponse({
  Map<String, List<String>>? headers,
  List<Cookie>? cookies,
  BytesBuilder? body,
}) {
  final mockResponse = MockHttpResponse();
  headers ??= {};
  body ??= BytesBuilder();

  // Track real HttpResponse-like state
  var headersSent = false;
  var bodyStarted = false;
  var closed = false;

  void ensureHeadersNotSent() {
    if (headersSent || bodyStarted || closed) {
      throw StateError('Header already sent');
    }
  }

  void ensureNotClosed() {
    if (closed) {
      throw StateError('Response is closed');
    }
  }

  // Setup cookies
  if (cookies != null && cookies.isNotEmpty) {
    headers[HttpHeaders.cookieHeader] = cookies
        .map((cookie) => '${cookie.name}=${cookie.value}')
        .toList();
  }

  headers.remove(HttpHeaders.cookieHeader);

  // Create a synced cookie list that automatically updates headers
  final syncedCookieList = SyncedCookieList([...?cookies], headers);
  when(mockResponse.cookies).thenAnswer((_) => syncedCookieList);

  int statusCode = HttpStatus.ok;
  final mockResponseHeaders = setupHeaders(headers);
  when(mockResponse.statusCode).thenAnswer((_) => statusCode);
  when(mockResponse.statusCode = any).thenAnswer((invocation) {
    ensureHeadersNotSent();
    statusCode = invocation.positionalArguments.first as int;
  });

  // Mock headers getter and setup headers
  when(mockResponse.headers).thenAnswer((i) => mockResponseHeaders);

  // write/add/addStream mark body started and implicitly send headers
  when(mockResponse.write(any)).thenAnswer((invocation) {
    ensureNotClosed();
    headersSent = true;
    bodyStarted = true;
    final data = invocation.positionalArguments[0].toString();
    body?.add(utf8.encode(data));
  });

  when(mockResponse.addStream(any)).thenAnswer((invocation) async {
    ensureNotClosed();
    headersSent = true;
    bodyStarted = true;
    final stream = invocation.positionalArguments[0] as Stream<List<int>>;
    await for (final chunk in stream) {
      body?.add(chunk);
    }
  });

  when(mockResponse.add(any)).thenAnswer((invocation) {
    ensureNotClosed();
    headersSent = true;
    bodyStarted = true;
    final data = invocation.positionalArguments[0] as List<int>;
    body?.add(data);
  });

  // Mock close method to finalize the response
  when(mockResponse.close()).thenAnswer((_) async {
    ensureNotClosed();
    headersSent = true;
    closed = true;
  });

  return mockResponse;
}