debug_test.dart 9.44 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5 6 7 8 9 10
// TODO(gspencergoog): Remove this tag once this test's state leaks/test
// dependencies have been fixed.
// https://github.com/flutter/flutter/issues/85160
// Fails with "flutter test --test-randomize-ordering-seed=123"
@Tags(<String>['no-shuffle'])

11 12 13 14 15 16 17 18 19 20 21 22 23
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,
24
      children: children,
25
    );
26
    late FlutterError error;
27 28 29 30 31 32 33 34 35 36 37 38 39 40
    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'
41
          '   crossAxisAlignment: center) has multiple children with key\n'
42
          "   [<'key'>].\n",
43 44 45 46 47 48 49 50 51 52 53
        ),
      );
    }
  });

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

  testWidgets('debugCheckHasTable control test', (WidgetTester tester) async {
    await tester.pumpWidget(
      Builder(
        builder: (BuildContext context) {
75
          late FlutterError error;
76 77 78 79 80 81 82
          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
83
            expect(error.diagnostics[2], isA<DiagnosticsProperty<Element>>());
84 85 86 87 88 89 90 91 92
            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'
93
                '     [root]"\n',
94 95 96 97
              ),
            );
          }
          return Container();
98
        },
99 100 101 102 103 104 105 106
      ),
    );
  });

  testWidgets('debugCheckHasMediaQuery control test', (WidgetTester tester) async {
    await tester.pumpWidget(
      Builder(
        builder: (BuildContext context) {
107
          late FlutterError error;
108 109 110 111 112 113 114
          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
115
            expect(error.diagnostics[2], isA<DiagnosticsProperty<Element>>());
116 117 118 119
            expect(error.diagnostics.last.level, DiagnosticLevel.hint);
            expect(
              error.diagnostics.last.toStringDeep(),
              equalsIgnoringHashCodes(
120 121 122 123
                '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'
124
                'context you use comes from a widget above those widgets.\n',
125 126 127 128 129 130
              ),
            );
            expect(
              error.toStringDeep(),
              equalsIgnoringHashCodes(
                'FlutterError\n'
131
                '   No MediaQuery widget ancestor found.\n'
132 133 134 135 136 137
                '   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'
138 139 140 141
                '   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'
142
                '   context you use comes from a widget above those widgets.\n',
143 144 145 146
              ),
            );
          }
          return Container();
147
        },
148 149 150 151 152 153
      ),
    );
  });

  test('debugWidgetBuilderValue control test', () {
    final Widget widget = Container();
154
    FlutterError? error;
155 156 157 158 159 160
    try {
      debugWidgetBuilderValue(widget, null);
    } on FlutterError catch (e) {
      error = e;
    } finally {
      expect(error, isNotNull);
161
      expect(error!.diagnostics.length, 4);
Dan Field's avatar
Dan Field committed
162
      expect(error.diagnostics[1], isA<DiagnosticsProperty<Widget>>());
163 164 165 166 167
      expect(error.diagnostics[1].style, DiagnosticsTreeStyle.errorProperty);
      expect(
        error.diagnostics[1].toStringDeep(),
        equalsIgnoringHashCodes(
          'The offending widget is:\n'
168 169
          '  Container\n',
        ),
170 171 172 173 174 175 176 177 178 179
      );
      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',
180
        ),
181 182 183 184 185 186 187 188 189 190 191 192
      );
      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'
193
          '   0.0, height: 0.0)".\n',
194 195 196 197 198 199 200 201 202 203
        ),
      );
      error = null;
    }
    try {
      debugWidgetBuilderValue(widget, widget);
    } on FlutterError catch (e) {
      error = e;
    } finally {
      expect(error, isNotNull);
204
      expect(error!.diagnostics.length, 3);
Dan Field's avatar
Dan Field committed
205
      expect(error.diagnostics[1], isA<DiagnosticsProperty<Widget>>());
206 207 208 209 210
      expect(error.diagnostics[1].style, DiagnosticsTreeStyle.errorProperty);
      expect(
        error.diagnostics[1].toStringDeep(),
        equalsIgnoringHashCodes(
          'The offending widget is:\n'
211 212
          '  Container\n',
        ),
213 214 215 216 217 218 219 220
      );
      expect(
        error.toStringDeep(),
        equalsIgnoringHashCodes(
          'FlutterError\n'
          '   A build function returned context.widget.\n'
          '   The offending widget is:\n'
          '     Container\n'
221
          "   Build functions must never return their BuildContext parameter's\n"
222 223
          '   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'
224
          '   crash.\n',
225 226 227 228 229
        ),
      );
    }
  });

230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
  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),
        ),
      ),
    );

248 249 250 251 252 253 254 255
    expect(
      () => debugCheckHasWidgetsLocalizations(noLocalizationsAvailable.currentContext!),
      throwsA(isAssertionError.having(
        (AssertionError e) => e.message,
        'message',
        contains('No WidgetsLocalizations found'),
      )),
    );
256 257 258 259

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

260 261
  test('debugAssertAllWidgetVarsUnset', () {
    debugHighlightDeprecatedWidgets = true;
262
    late FlutterError error;
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
    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',
      );
    }
  });
}