multichild_test.dart 10.7 KB
Newer Older
Hixie's avatar
Hixie committed
1 2 3 4
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

Adam Barth's avatar
Adam Barth committed
5
import 'package:flutter_test/flutter_test.dart';
6 7
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
8 9 10 11

import 'test_widgets.dart';

void checkTree(WidgetTester tester, List<BoxDecoration> expectedDecorations) {
12
  final MultiChildRenderObjectElement element = tester.element(find.byElementPredicate(
13 14
    (Element element) => element is MultiChildRenderObjectElement
  ));
15 16
  expect(element, isNotNull);
  expect(element.renderObject is RenderStack, isTrue);
17
  final RenderStack renderObject = element.renderObject;
18 19 20 21
  try {
    RenderObject child = renderObject.firstChild;
    for (BoxDecoration decoration in expectedDecorations) {
      expect(child is RenderDecoratedBox, isTrue);
22
      final RenderDecoratedBox decoratedBox = child;
23
      expect(decoratedBox.decoration, equals(decoration));
24 25
      final StackParentData decoratedBoxParentData = decoratedBox.parentData;
      child = decoratedBoxParentData.nextSibling;
26 27 28 29 30 31 32 33
    }
    expect(child, isNull);
  } catch (e) {
    print(renderObject.toStringDeep());
    rethrow;
  }
}

34 35 36 37 38 39 40
class MockMultiChildRenderObjectWidget extends MultiChildRenderObjectWidget {
  MockMultiChildRenderObjectWidget({ Key key, List<Widget> children }) : super(key: key, children: children);

  @override
  RenderObject createRenderObject(BuildContext context) => null;
}

41
void main() {
42
  testWidgets('MultiChildRenderObjectElement control test', (WidgetTester tester) async {
43

44
    await tester.pumpWidget(
45
      Stack(
46
        textDirection: TextDirection.ltr,
47
        children: const <Widget>[
48 49 50
          DecoratedBox(decoration: kBoxDecorationA),
          DecoratedBox(decoration: kBoxDecorationB),
          DecoratedBox(decoration: kBoxDecorationC),
51 52
        ],
      ),
53 54 55 56
    );

    checkTree(tester, <BoxDecoration>[kBoxDecorationA, kBoxDecorationB, kBoxDecorationC]);

57
    await tester.pumpWidget(
58
      Stack(
59
        textDirection: TextDirection.ltr,
60
        children: const <Widget>[
61 62
          DecoratedBox(decoration: kBoxDecorationA),
          DecoratedBox(decoration: kBoxDecorationC),
63 64
        ],
      ),
65 66 67 68
    );

    checkTree(tester, <BoxDecoration>[kBoxDecorationA, kBoxDecorationC]);

69
    await tester.pumpWidget(
70
      Stack(
71
        textDirection: TextDirection.ltr,
72
        children: const <Widget>[
73 74 75
          DecoratedBox(decoration: kBoxDecorationA),
          DecoratedBox(key: Key('b'), decoration: kBoxDecorationB),
          DecoratedBox(decoration: kBoxDecorationC),
76 77
        ],
      ),
78 79 80 81
    );

    checkTree(tester, <BoxDecoration>[kBoxDecorationA, kBoxDecorationB, kBoxDecorationC]);

82
    await tester.pumpWidget(
83
      Stack(
84
        textDirection: TextDirection.ltr,
85
        children: const <Widget>[
86 87 88
          DecoratedBox(key: Key('b'), decoration: kBoxDecorationB),
          DecoratedBox(decoration: kBoxDecorationC),
          DecoratedBox(key: Key('a'), decoration: kBoxDecorationA),
89 90
        ],
      ),
91 92 93 94
    );

    checkTree(tester, <BoxDecoration>[kBoxDecorationB, kBoxDecorationC, kBoxDecorationA]);

95
    await tester.pumpWidget(
96
      Stack(
97
        textDirection: TextDirection.ltr,
98
        children: const <Widget>[
99 100 101
          DecoratedBox(key: Key('a'), decoration: kBoxDecorationA),
          DecoratedBox(decoration: kBoxDecorationC),
          DecoratedBox(key: Key('b'), decoration: kBoxDecorationB),
102 103
        ],
      ),
104 105 106 107
    );

    checkTree(tester, <BoxDecoration>[kBoxDecorationA, kBoxDecorationC, kBoxDecorationB]);

108
    await tester.pumpWidget(
109
      Stack(
110
        textDirection: TextDirection.ltr,
111
        children: const <Widget>[
112
          DecoratedBox(decoration: kBoxDecorationC),
113 114
        ],
      ),
115 116 117 118
    );

    checkTree(tester, <BoxDecoration>[kBoxDecorationC]);

119
    await tester.pumpWidget(
120
      Stack(textDirection: TextDirection.ltr)
121 122 123 124
    );

    checkTree(tester, <BoxDecoration>[]);

125 126
  });

127
  testWidgets('MultiChildRenderObjectElement with stateless widgets', (WidgetTester tester) async {
128

129
    await tester.pumpWidget(
130
      Stack(
131
        textDirection: TextDirection.ltr,
132
        children: const <Widget>[
133 134 135
          DecoratedBox(decoration: kBoxDecorationA),
          DecoratedBox(decoration: kBoxDecorationB),
          DecoratedBox(decoration: kBoxDecorationC),
136 137
        ],
      ),
138 139 140 141
    );

    checkTree(tester, <BoxDecoration>[kBoxDecorationA, kBoxDecorationB, kBoxDecorationC]);

142
    await tester.pumpWidget(
143
      Stack(
144
        textDirection: TextDirection.ltr,
145
        children: <Widget>[
146
          const DecoratedBox(decoration: kBoxDecorationA),
147
          Container(
148
            child: const DecoratedBox(decoration: kBoxDecorationB),
149
          ),
150
          const DecoratedBox(decoration: kBoxDecorationC),
151 152
        ],
      ),
153 154 155 156
    );

    checkTree(tester, <BoxDecoration>[kBoxDecorationA, kBoxDecorationB, kBoxDecorationC]);

157
    await tester.pumpWidget(
158
      Stack(
159
        textDirection: TextDirection.ltr,
160
        children: <Widget>[
161
          const DecoratedBox(decoration: kBoxDecorationA),
162 163
          Container(
            child: Container(
164
              child: const DecoratedBox(decoration: kBoxDecorationB),
165
            ),
166
          ),
167
          const DecoratedBox(decoration: kBoxDecorationC),
168 169
        ],
      ),
170 171 172 173
    );

    checkTree(tester, <BoxDecoration>[kBoxDecorationA, kBoxDecorationB, kBoxDecorationC]);

174
    await tester.pumpWidget(
175
      Stack(
176
        textDirection: TextDirection.ltr,
177
        children: <Widget>[
178 179
          Container(
            child: Container(
180
              child: const DecoratedBox(decoration: kBoxDecorationB),
181
            ),
182
          ),
183
          Container(
184
            child: const DecoratedBox(decoration: kBoxDecorationA),
185
          ),
186
          const DecoratedBox(decoration: kBoxDecorationC),
187 188
        ],
      ),
189 190 191 192
    );

    checkTree(tester, <BoxDecoration>[kBoxDecorationB, kBoxDecorationA, kBoxDecorationC]);

193
    await tester.pumpWidget(
194
      Stack(
195
        textDirection: TextDirection.ltr,
196
        children: <Widget>[
197
          Container(
198
            child: const DecoratedBox(decoration: kBoxDecorationB),
199
          ),
200
          Container(
201
            child: const DecoratedBox(decoration: kBoxDecorationA),
202
          ),
203
          const DecoratedBox(decoration: kBoxDecorationC),
204 205
        ],
      ),
206 207 208 209
    );

    checkTree(tester, <BoxDecoration>[kBoxDecorationB, kBoxDecorationA, kBoxDecorationC]);

210
    await tester.pumpWidget(
211
      Stack(
212
        textDirection: TextDirection.ltr,
213
        children: <Widget>[
214
          Container(
215
            key: const Key('b'),
216
            child: const DecoratedBox(decoration: kBoxDecorationB),
217
          ),
218
          Container(
219
            key: const Key('a'),
220
            child: const DecoratedBox(decoration: kBoxDecorationA),
221
          ),
222 223
        ],
      ),
224 225 226 227
    );

    checkTree(tester, <BoxDecoration>[kBoxDecorationB, kBoxDecorationA]);

228
    await tester.pumpWidget(
229
      Stack(
230
        textDirection: TextDirection.ltr,
231
        children: <Widget>[
232
          Container(
233
            key: const Key('a'),
234
            child: const DecoratedBox(decoration: kBoxDecorationA),
235
          ),
236
          Container(
237
            key: const Key('b'),
238
            child: const DecoratedBox(decoration: kBoxDecorationB),
239
          ),
240 241
        ],
      ),
242 243 244 245
    );

    checkTree(tester, <BoxDecoration>[kBoxDecorationA, kBoxDecorationB]);

246
    await tester.pumpWidget(
247
      Stack(textDirection: TextDirection.ltr)
248 249 250
    );

    checkTree(tester, <BoxDecoration>[]);
251 252
  });

253 254
  testWidgets('MultiChildRenderObjectElement with stateful widgets', (WidgetTester tester) async {
    await tester.pumpWidget(
255
      Stack(
256
        textDirection: TextDirection.ltr,
257
        children: const <Widget>[
258 259
          DecoratedBox(decoration: kBoxDecorationA),
          DecoratedBox(decoration: kBoxDecorationB),
260 261
        ],
      ),
262 263 264 265
    );

    checkTree(tester, <BoxDecoration>[kBoxDecorationA, kBoxDecorationB]);

266
    await tester.pumpWidget(
267
      Stack(
268
        textDirection: TextDirection.ltr,
269
        children: const <Widget>[
270 271 272
          FlipWidget(
            left: DecoratedBox(decoration: kBoxDecorationA),
            right: DecoratedBox(decoration: kBoxDecorationB),
273
          ),
274
          DecoratedBox(decoration: kBoxDecorationC),
275 276
        ],
      ),
277 278 279 280 281
    );

    checkTree(tester, <BoxDecoration>[kBoxDecorationA, kBoxDecorationC]);

    flipStatefulWidget(tester);
282
    await tester.pump();
283 284 285

    checkTree(tester, <BoxDecoration>[kBoxDecorationB, kBoxDecorationC]);

286
    await tester.pumpWidget(
287
      Stack(
288
        textDirection: TextDirection.ltr,
289
        children: const <Widget>[
290 291 292
          FlipWidget(
            left: DecoratedBox(decoration: kBoxDecorationA),
            right: DecoratedBox(decoration: kBoxDecorationB),
293
          ),
294 295
        ],
      ),
296 297 298 299 300
    );

    checkTree(tester, <BoxDecoration>[kBoxDecorationB]);

    flipStatefulWidget(tester);
301
    await tester.pump();
302 303 304

    checkTree(tester, <BoxDecoration>[kBoxDecorationA]);

305
    await tester.pumpWidget(
306
      Stack(
307
        textDirection: TextDirection.ltr,
308
        children: const <Widget>[
309 310 311 312
          FlipWidget(
            key: Key('flip'),
            left: DecoratedBox(decoration: kBoxDecorationA),
            right: DecoratedBox(decoration: kBoxDecorationB),
313
          ),
314 315
        ],
      ),
316 317
    );

318
    await tester.pumpWidget(
319
      Stack(
320
        textDirection: TextDirection.ltr,
321
        children: const <Widget>[
322 323 324 325 326
          DecoratedBox(key: Key('c'), decoration: kBoxDecorationC),
          FlipWidget(
            key: Key('flip'),
            left: DecoratedBox(decoration: kBoxDecorationA),
            right: DecoratedBox(decoration: kBoxDecorationB),
327
          ),
328 329
        ],
      ),
330 331 332 333 334
    );

    checkTree(tester, <BoxDecoration>[kBoxDecorationC, kBoxDecorationA]);

    flipStatefulWidget(tester);
335
    await tester.pump();
336 337 338

    checkTree(tester, <BoxDecoration>[kBoxDecorationC, kBoxDecorationB]);

339
    await tester.pumpWidget(
340
      Stack(
341
        textDirection: TextDirection.ltr,
342
        children: const <Widget>[
343 344 345 346
          FlipWidget(
            key: Key('flip'),
            left: DecoratedBox(decoration: kBoxDecorationA),
            right: DecoratedBox(decoration: kBoxDecorationB),
347
          ),
348
          DecoratedBox(key: Key('c'), decoration: kBoxDecorationC),
349 350
        ],
      ),
351 352 353
    );

    checkTree(tester, <BoxDecoration>[kBoxDecorationB, kBoxDecorationC]);
354
  });
355 356 357 358 359 360 361 362 363 364 365 366 367

  // Regression test for https://github.com/flutter/flutter/issues/37136.
  test('provides useful assertion message when one of the children is null', () {
    bool assertionTriggered = false;
    try {
      MockMultiChildRenderObjectWidget(children: const <Widget>[null]);
    } catch (e) {
      expect(e.toString(), contains("MockMultiChildRenderObjectWidget's children must not contain any null values,"));
      assertionTriggered = true;
    }

    expect(assertionTriggered, isTrue);
  });
368
}