4

A minimal reproducible example can be found here: https://github.com/HerrNiklasRaab/repro-widget-test-overflow

My current app looks like this:

import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(
      home: Scaffold(
    body: DashboardNewsItem(),
  )));
}

class DashboardNewsItem extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.green,
      width: 165,
      height: 100,
      child: Row(
        children: <Widget>[
          Text(
            "Zu Instagram",
          ),
          Icon(Icons.arrow_forward)
        ],
      ),
    );
  }
}

If I run this on the device it looks like the following: enter image description here

Once I run this with the following widget test:

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:test_ble/main.dart';

void main() {
  testWidgets('Counter increments smoke test', (WidgetTester tester) async {
    await tester.pumpWidget(MaterialApp(
        home: Scaffold(
      body: DashboardNewsItem(),
    )));
  });
}

I get this exception:

Counter increments smoke test:

══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞═════════════════════════════════════════════════════════
The following assertion was thrown during layout:
A RenderFlex overflowed by 27 pixels on the right.

The relevant error-causing widget was:
  Row file:///Users/niklasraab/GitHub/test_ble/lib/main.dart:19:14

The overflowing RenderFlex has an orientation of Axis.horizontal.
The edge of the RenderFlex that is overflowing has been marked in the rendering with a yellow and
black striped pattern. This is usually caused by the contents being too big for the RenderFlex.
Consider applying a flex factor (e.g. using an Expanded widget) to force the children of the
RenderFlex to fit within the available space instead of being sized to their natural size.
This is considered an error condition because it indicates that there is content that cannot be
seen. If the content is legitimately bigger than the available space, consider clipping it with a
ClipRect widget before putting it in the flex, or using a scrollable container rather than a Flex,
like a ListView.
The specific RenderFlex in question is: RenderFlex#abc37 OVERFLOWING:
  creator: Row ← ColoredBox ← ConstrainedBox ← Container ← DashboardNewsItem ← _BodyBuilder ←
    MediaQuery ← LayoutId-[<_ScaffoldSlot.body>] ← CustomMultiChildLayout ← AnimatedBuilder ←
    DefaultTextStyle ← AnimatedDefaultTextStyle ← ⋯
  parentData: <none> (can use size)
  constraints: BoxConstraints(w=165.0, h=100.0)
  size: Size(165.0, 100.0)
  direction: horizontal
  mainAxisAlignment: start
  mainAxisSize: max
  crossAxisAlignment: center
  textDirection: ltr
  verticalDirection: down
◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤
════════════════════════════════════════════════════════════════════════════════════════════════════
ERROR: Test failed. See exception logs above.
The test description was: Counter increments smoke test

Off course I could just wrap the Text inside a Flexible like this:

class DashboardNewsItem extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.green,
      width: 165,
      height: 100,
      child: Row(
        children: <Widget>[
          Flexible(
            child: Text(
              "Zu Instagram",
            ),
          ),
          Icon(Icons.arrow_forward)
        ],
      ),
    );
  }
}

But I should not need to do that, because the Text has enough space on the horizontal axis. So can anyone explain this wired behavior to me?

Niklas Raab
  • 1,576
  • 1
  • 16
  • 32

1 Answers1

3

If you run the test directly on the emulator it'll pass.

flutter run -d emulator test\widget_test.dart

I personally ran it directly on my device and the test passed.

The problem is that it won't pass on all devices. On some devices 165 logical pixels of width might not be enough to contain the Text and the Icon. Probably that's true for the default testing environment that is provided by Flutter. Generally it's a good idea to have your widgets as responsive as possible. Thus, a better implementation would be removing the width and height constraints, constraining the size of the Row instead, and using padding.

class DashboardNewsItem extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.green,
      padding: const EdgeInsets.symmetric(
          horizontal: 24.0, vertical: 16.0), // or any other value
      child: Row(
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          Text(
            "Zu Instagram",
          ),
          Icon(Icons.arrow_forward)
        ],
      ),
    );
  }
}
NetanZaf
  • 1,003
  • 8
  • 7
  • Thanks for testing this. I can confirm, that this test runs on the device to. I agree that you should develop as much responsible as possible. But in this case, we really want those absolute dimensions. The normal widget testing environment has this Size(400, 600), so this should be possible. – Niklas Raab Apr 19 '20 at 16:40
  • 1
    You'll have to wrap the Text with an Expanded to ensure that in the case of limited space, the text would wrap to the next line. – NetanZaf Apr 19 '20 at 18:22
  • Yes, this is more or less what I described in the Question, as soon as you wrap a flex widget around the text it works. But I want to know why it doesn't work without it in the widget testing environment. – Niklas Raab Apr 19 '20 at 18:49
  • I've checked this and in the testing environment the size of the row is (192.0, 24.0). You can see that the width in longer than 165, and that's the reason it overflows. There is no reason why you'd want this dimensions: (1) it won't work on all devices and (2) these are not absolute dimensions; for two devices in the exact same size, 165 might mean the entire screen for one of the devices, while it could mean only half of it for the other. read about logical resolutions. – NetanZaf Apr 20 '20 at 10:24
  • 2
    If you want to set a specific surface for you test, this [answer](https://stackoverflow.com/a/53707065/11527) may help you. – Ber Jan 04 '21 at 11:20