multichild_test.dart 10.6 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
Hixie's avatar
Hixie committed
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
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
7
import 'package:flutter_test/flutter_test.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
  expect(element, isNotNull);
Dan Field's avatar
Dan Field committed
16
  expect(element.renderObject, isA<RenderStack>());
17
  final RenderStack renderObject = element.renderObject as RenderStack;
18
  try {
19
    RenderObject? child = renderObject.firstChild;
20
    for (final BoxDecoration decoration in expectedDecorations) {
Dan Field's avatar
Dan Field committed
21
      expect(child, isA<RenderDecoratedBox>());
22
      final RenderDecoratedBox decoratedBox = child! as RenderDecoratedBox;
23
      expect(decoratedBox.decoration, equals(decoration));
24
      final StackParentData decoratedBoxParentData = decoratedBox.parentData! as StackParentData;
25
      child = decoratedBoxParentData.nextSibling;
26 27 28 29 30 31 32 33
    }
    expect(child, isNull);
  } catch (e) {
    print(renderObject.toStringDeep());
    rethrow;
  }
}

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

  @override
38 39 40 41
  RenderObject createRenderObject(BuildContext context) {
    assert(false);
    return FakeRenderObject();
  }
42 43
}

44
void main() {
45
  testWidgets('MultiChildRenderObjectElement control test', (WidgetTester tester) async {
46

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

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

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

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

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

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

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

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

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

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

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

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

122
    await tester.pumpWidget(
123
      Stack(textDirection: TextDirection.ltr)
124 125 126 127
    );

    checkTree(tester, <BoxDecoration>[]);

128 129
  });

130
  testWidgets('MultiChildRenderObjectElement with stateless widgets', (WidgetTester tester) async {
131

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

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

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

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

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

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

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

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

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

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

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

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

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

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

249
    await tester.pumpWidget(
250
      Stack(textDirection: TextDirection.ltr)
251 252 253
    );

    checkTree(tester, <BoxDecoration>[]);
254 255
  });

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

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

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

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

    flipStatefulWidget(tester);
285
    await tester.pump();
286 287 288

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

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

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

    flipStatefulWidget(tester);
304
    await tester.pump();
305 306 307

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

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

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

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

    flipStatefulWidget(tester);
338
    await tester.pump();
339 340 341

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

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

    checkTree(tester, <BoxDecoration>[kBoxDecorationB, kBoxDecorationC]);
357
  });
358
}
359

360 361 362 363 364
class FakeRenderObject extends RenderBox {
  @override
  void performLayout() {
    size = constraints.biggest;
  }
365
}
366 367 368 369 370 371 372 373 374

class DummyWidget extends StatelessWidget {
  const DummyWidget({ Key? key, required this.child }) : super(key: key);

  final Widget child;

  @override
  Widget build(BuildContext context) => child;
}