debug_test.dart 9.2 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
  test('debugChildrenHaveDuplicateKeys control test', () {
    const Key key = Key('key');
    final List<Widget> children = <Widget>[
      Container(key: key),
      Container(key: key),
    ];
    final Widget widget = Flex(
      direction: Axis.vertical,
18
      children: children,
19
    );
20
    late FlutterError error;
21 22 23 24 25 26 27 28 29 30 31 32 33 34
    try {
      debugChildrenHaveDuplicateKeys(widget, children);
    } on FlutterError catch (e) {
      error = e;
    } finally {
      expect(error, isNotNull);
      expect(
        error.toStringDeep(),
        equalsIgnoringHashCodes(
          'FlutterError\n'
          '   Duplicate keys found.\n'
          '   If multiple keyed nodes exist as children of another node, they\n'
          '   must have unique keys.\n'
          '   Flex(direction: vertical, mainAxisAlignment: start,\n'
35
          '   crossAxisAlignment: center) has multiple children with key\n'
36
          "   [<'key'>].\n",
37 38 39 40 41 42 43 44 45 46 47
        ),
      );
    }
  });

  test('debugItemsHaveDuplicateKeys control test', () {
    const Key key = Key('key');
    final List<Widget> items = <Widget>[
      Container(key: key),
      Container(key: key),
    ];
48
    late FlutterError error;
49 50 51 52 53 54 55 56 57 58
    try {
      debugItemsHaveDuplicateKeys(items);
    } on FlutterError catch (e) {
      error = e;
    } finally {
      expect(error, isNotNull);
      expect(
        error.toStringDeep(),
        equalsIgnoringHashCodes(
          'FlutterError\n'
59
          "   Duplicate key found: [<'key'>].\n",
60 61 62 63 64 65 66 67 68
        ),
      );
    }
  });

  testWidgets('debugCheckHasTable control test', (WidgetTester tester) async {
    await tester.pumpWidget(
      Builder(
        builder: (BuildContext context) {
69
          late FlutterError error;
70 71 72 73 74 75 76
          try {
            debugCheckHasTable(context);
          } on FlutterError catch (e) {
            error = e;
          } finally {
            expect(error, isNotNull);
            expect(error.diagnostics.length, 4);
Dan Field's avatar
Dan Field committed
77
            expect(error.diagnostics[2], isA<DiagnosticsProperty<Element>>());
78 79 80 81 82 83 84 85 86
            expect(
              error.toStringDeep(),
              equalsIgnoringHashCodes(
                'FlutterError\n'
                '   No Table widget found.\n'
                '   Builder widgets require a Table widget ancestor.\n'
                '   The specific widget that could not find a Table ancestor was:\n'
                '     Builder\n'
                '   The ownership chain for the affected widget is: "Builder ←\n'
87
                '     [root]"\n',
88 89 90 91
              ),
            );
          }
          return Container();
92
        },
93 94 95 96 97 98 99 100
      ),
    );
  });

  testWidgets('debugCheckHasMediaQuery control test', (WidgetTester tester) async {
    await tester.pumpWidget(
      Builder(
        builder: (BuildContext context) {
101
          late FlutterError error;
102 103 104 105 106 107 108
          try {
            debugCheckHasMediaQuery(context);
          } on FlutterError catch (e) {
            error = e;
          } finally {
            expect(error, isNotNull);
            expect(error.diagnostics.length, 5);
Dan Field's avatar
Dan Field committed
109
            expect(error.diagnostics[2], isA<DiagnosticsProperty<Element>>());
110 111 112 113
            expect(error.diagnostics.last.level, DiagnosticLevel.hint);
            expect(
              error.diagnostics.last.toStringDeep(),
              equalsIgnoringHashCodes(
114 115 116 117
                'No MediaQuery ancestor could be found starting from the context\n'
                'that was passed to MediaQuery.of(). This can happen because you\n'
                'have not added a WidgetsApp, CupertinoApp, or MaterialApp widget\n'
                '(those widgets introduce a MediaQuery), or it can happen if the\n'
118
                'context you use comes from a widget above those widgets.\n',
119 120 121 122 123 124
              ),
            );
            expect(
              error.toStringDeep(),
              equalsIgnoringHashCodes(
                'FlutterError\n'
125
                '   No MediaQuery widget ancestor found.\n'
126 127 128 129 130 131
                '   Builder widgets require a MediaQuery widget ancestor.\n'
                '   The specific widget that could not find a MediaQuery ancestor\n'
                '   was:\n'
                '     Builder\n'
                '   The ownership chain for the affected widget is: "Builder ←\n'
                '     [root]"\n'
132 133 134 135
                '   No MediaQuery ancestor could be found starting from the context\n'
                '   that was passed to MediaQuery.of(). This can happen because you\n'
                '   have not added a WidgetsApp, CupertinoApp, or MaterialApp widget\n'
                '   (those widgets introduce a MediaQuery), or it can happen if the\n'
136
                '   context you use comes from a widget above those widgets.\n',
137 138 139 140
              ),
            );
          }
          return Container();
141
        },
142 143 144 145 146 147
      ),
    );
  });

  test('debugWidgetBuilderValue control test', () {
    final Widget widget = Container();
148
    FlutterError? error;
149 150 151 152 153 154
    try {
      debugWidgetBuilderValue(widget, null);
    } on FlutterError catch (e) {
      error = e;
    } finally {
      expect(error, isNotNull);
155
      expect(error!.diagnostics.length, 4);
Dan Field's avatar
Dan Field committed
156
      expect(error.diagnostics[1], isA<DiagnosticsProperty<Widget>>());
157 158 159 160 161
      expect(error.diagnostics[1].style, DiagnosticsTreeStyle.errorProperty);
      expect(
        error.diagnostics[1].toStringDeep(),
        equalsIgnoringHashCodes(
          'The offending widget is:\n'
162 163
          '  Container\n',
        ),
164 165 166 167 168 169 170 171 172 173
      );
      expect(error.diagnostics[2].level, DiagnosticLevel.info);
      expect(error.diagnostics[3].level, DiagnosticLevel.hint);
      expect(
        error.diagnostics[3].toStringDeep(),
        equalsIgnoringHashCodes(
          'To return an empty space that causes the building widget to fill\n'
          'available room, return "Container()". To return an empty space\n'
          'that takes as little room as possible, return "Container(width:\n'
          '0.0, height: 0.0)".\n',
174
        ),
175 176 177 178 179 180 181 182 183 184 185 186
      );
      expect(
        error.toStringDeep(),
        equalsIgnoringHashCodes(
          'FlutterError\n'
          '   A build function returned null.\n'
          '   The offending widget is:\n'
          '     Container\n'
          '   Build functions must never return null.\n'
          '   To return an empty space that causes the building widget to fill\n'
          '   available room, return "Container()". To return an empty space\n'
          '   that takes as little room as possible, return "Container(width:\n'
187
          '   0.0, height: 0.0)".\n',
188 189 190 191 192 193 194 195 196 197
        ),
      );
      error = null;
    }
    try {
      debugWidgetBuilderValue(widget, widget);
    } on FlutterError catch (e) {
      error = e;
    } finally {
      expect(error, isNotNull);
198
      expect(error!.diagnostics.length, 3);
Dan Field's avatar
Dan Field committed
199
      expect(error.diagnostics[1], isA<DiagnosticsProperty<Widget>>());
200 201 202 203 204
      expect(error.diagnostics[1].style, DiagnosticsTreeStyle.errorProperty);
      expect(
        error.diagnostics[1].toStringDeep(),
        equalsIgnoringHashCodes(
          'The offending widget is:\n'
205 206
          '  Container\n',
        ),
207 208 209 210 211 212 213 214
      );
      expect(
        error.toStringDeep(),
        equalsIgnoringHashCodes(
          'FlutterError\n'
          '   A build function returned context.widget.\n'
          '   The offending widget is:\n'
          '     Container\n'
215
          "   Build functions must never return their BuildContext parameter's\n"
216 217
          '   widget or a child that contains "context.widget". Doing so\n'
          '   introduces a loop in the widget tree that can cause the app to\n'
218
          '   crash.\n',
219 220 221 222 223
        ),
      );
    }
  });

224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
  testWidgets('debugCheckHasWidgetsLocalizations throws', (WidgetTester tester) async {
    final GlobalKey noLocalizationsAvailable = GlobalKey();
    final GlobalKey localizationsAvailable = GlobalKey();

    await tester.pumpWidget(
      Container(
        key: noLocalizationsAvailable,
        child: WidgetsApp(
          builder: (BuildContext context, Widget? child) {
            return Container(
              key: localizationsAvailable,
            );
          },
          color: const Color(0xFF4CAF50),
        ),
      ),
    );

242 243 244 245 246 247 248 249
    expect(
      () => debugCheckHasWidgetsLocalizations(noLocalizationsAvailable.currentContext!),
      throwsA(isAssertionError.having(
        (AssertionError e) => e.message,
        'message',
        contains('No WidgetsLocalizations found'),
      )),
    );
250 251 252 253

    expect(debugCheckHasWidgetsLocalizations(localizationsAvailable.currentContext!), isTrue);
  });

254 255
  test('debugAssertAllWidgetVarsUnset', () {
    debugHighlightDeprecatedWidgets = true;
256
    late FlutterError error;
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
    try {
      debugAssertAllWidgetVarsUnset('The value of a widget debug variable was changed by the test.');
    } on FlutterError catch (e) {
      error = e;
    } finally {
      expect(error, isNotNull);
      expect(error.diagnostics.length, 1);
      expect(
        error.toStringDeep(),
        'FlutterError\n'
        '   The value of a widget debug variable was changed by the test.\n',
      );
    }
  });
}