reparent_state_test.dart 10.5 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.

Adam Barth's avatar
Adam Barth committed
5
import 'package:flutter_test/flutter_test.dart';
6
import 'package:flutter/widgets.dart';
7

8
class StateMarker extends StatefulWidget {
9
  const StateMarker({ Key key, this.child }) : super(key: key);
10 11 12

  final Widget child;

13
  @override
14
  StateMarkerState createState() => StateMarkerState();
15 16 17 18 19
}

class StateMarkerState extends State<StateMarker> {
  String marker;

20
  @override
21
  Widget build(BuildContext context) {
22 23
    if (widget.child != null)
      return widget.child;
24
    return Container();
25 26 27
  }
}

28
class DeactivateLogger extends StatefulWidget {
29
  const DeactivateLogger({ Key key, this.log }) : super(key: key);
30 31 32 33

  final List<String> log;

  @override
34
  DeactivateLoggerState createState() => DeactivateLoggerState();
35 36 37 38 39
}

class DeactivateLoggerState extends State<DeactivateLogger> {
  @override
  void deactivate() {
40
    widget.log.add('deactivate');
41 42 43 44 45
    super.deactivate();
  }

  @override
  Widget build(BuildContext context) {
46
    widget.log.add('build');
47
    return Container();
48 49 50
  }
}

51
void main() {
52
  testWidgets('can reparent state', (WidgetTester tester) async {
53 54
    final GlobalKey left = GlobalKey();
    final GlobalKey right = GlobalKey();
55

56
    const StateMarker grandchild = StateMarker();
57
    await tester.pumpWidget(
58
      Stack(
59
        textDirection: TextDirection.ltr,
60
        children: <Widget>[
61
          Container(
62
            child: StateMarker(key: left),
63
          ),
64 65
          Container(
            child: StateMarker(
66
              key: right,
67 68
              child: grandchild,
            ),
69
          ),
70
        ],
71
      ),
72
    );
73

74
    final StateMarkerState leftState = left.currentState as StateMarkerState;
Ian Hickson's avatar
Ian Hickson committed
75
    leftState.marker = 'left';
76
    final StateMarkerState rightState = right.currentState as StateMarkerState;
Ian Hickson's avatar
Ian Hickson committed
77
    rightState.marker = 'right';
78

79
    final StateMarkerState grandchildState = tester.state(find.byWidget(grandchild));
80
    expect(grandchildState, isNotNull);
Ian Hickson's avatar
Ian Hickson committed
81
    grandchildState.marker = 'grandchild';
82

83
    const StateMarker newGrandchild = StateMarker();
84
    await tester.pumpWidget(
85
      Stack(
86
        textDirection: TextDirection.ltr,
87
        children: <Widget>[
88 89
          Container(
            child: StateMarker(
90
              key: right,
91 92
              child: newGrandchild,
            ),
93
          ),
94
          Container(
95
            child: StateMarker(key: left),
96
          ),
97
        ],
98
      ),
99 100 101
    );

    expect(left.currentState, equals(leftState));
Ian Hickson's avatar
Ian Hickson committed
102
    expect(leftState.marker, equals('left'));
103
    expect(right.currentState, equals(rightState));
Ian Hickson's avatar
Ian Hickson committed
104
    expect(rightState.marker, equals('right'));
105

106
    final StateMarkerState newGrandchildState = tester.state(find.byWidget(newGrandchild));
107 108
    expect(newGrandchildState, isNotNull);
    expect(newGrandchildState, equals(grandchildState));
Ian Hickson's avatar
Ian Hickson committed
109
    expect(newGrandchildState.marker, equals('grandchild'));
110

111
    await tester.pumpWidget(
112 113 114
      Center(
        child: Container(
          child: StateMarker(
115
            key: left,
116 117 118
            child: Container(),
          ),
        ),
119
      ),
120
    );
121

122
    expect(left.currentState, equals(leftState));
Ian Hickson's avatar
Ian Hickson committed
123
    expect(leftState.marker, equals('left'));
124
    expect(right.currentState, isNull);
125 126
  });

127
  testWidgets('can reparent state with multichild widgets', (WidgetTester tester) async {
128 129
    final GlobalKey left = GlobalKey();
    final GlobalKey right = GlobalKey();
130

131
    const StateMarker grandchild = StateMarker();
132
    await tester.pumpWidget(
133
      Stack(
134
        textDirection: TextDirection.ltr,
135
        children: <Widget>[
136 137
          StateMarker(key: left),
          StateMarker(
138
            key: right,
139 140 141
            child: grandchild,
          ),
        ],
142
      ),
143
    );
144

145
    final StateMarkerState leftState = left.currentState as StateMarkerState;
Ian Hickson's avatar
Ian Hickson committed
146
    leftState.marker = 'left';
147
    final StateMarkerState rightState = right.currentState as StateMarkerState;
Ian Hickson's avatar
Ian Hickson committed
148
    rightState.marker = 'right';
149

150
    final StateMarkerState grandchildState = tester.state(find.byWidget(grandchild));
151
    expect(grandchildState, isNotNull);
Ian Hickson's avatar
Ian Hickson committed
152
    grandchildState.marker = 'grandchild';
153

154
    const StateMarker newGrandchild = StateMarker();
155
    await tester.pumpWidget(
156
      Stack(
157
        textDirection: TextDirection.ltr,
158
        children: <Widget>[
159
          StateMarker(
160
            key: right,
161
            child: newGrandchild,
162
          ),
163 164
          StateMarker(key: left),
        ],
165
      ),
166 167 168
    );

    expect(left.currentState, equals(leftState));
Ian Hickson's avatar
Ian Hickson committed
169
    expect(leftState.marker, equals('left'));
170
    expect(right.currentState, equals(rightState));
Ian Hickson's avatar
Ian Hickson committed
171
    expect(rightState.marker, equals('right'));
172

173
    final StateMarkerState newGrandchildState = tester.state(find.byWidget(newGrandchild));
174 175
    expect(newGrandchildState, isNotNull);
    expect(newGrandchildState, equals(grandchildState));
Ian Hickson's avatar
Ian Hickson committed
176
    expect(newGrandchildState.marker, equals('grandchild'));
177

178
    await tester.pumpWidget(
179 180 181
      Center(
        child: Container(
          child: StateMarker(
182
            key: left,
183 184 185
            child: Container(),
          ),
        ),
186
      ),
187
    );
188

189
    expect(left.currentState, equals(leftState));
Ian Hickson's avatar
Ian Hickson committed
190
    expect(leftState.marker, equals('left'));
191
    expect(right.currentState, isNull);
192 193
  });

194
  testWidgets('can with scrollable list', (WidgetTester tester) async {
195
    final GlobalKey key = GlobalKey();
196

197
    await tester.pumpWidget(StateMarker(key: key));
198

199
    final StateMarkerState keyState = key.currentState as StateMarkerState;
Ian Hickson's avatar
Ian Hickson committed
200
    keyState.marker = 'marked';
201

202
    await tester.pumpWidget(
203
      Directionality(
204
        textDirection: TextDirection.ltr,
205
        child: ListView(
206 207
          itemExtent: 100.0,
          children: <Widget>[
208
            Container(
209 210
              key: const Key('container'),
              height: 100.0,
211
              child: StateMarker(key: key),
212 213
            ),
          ],
214
        ),
215 216
      ),
    );
217

218
    expect(key.currentState, equals(keyState));
Ian Hickson's avatar
Ian Hickson committed
219
    expect(keyState.marker, equals('marked'));
220

221
    await tester.pumpWidget(StateMarker(key: key));
222

223
    expect(key.currentState, equals(keyState));
Ian Hickson's avatar
Ian Hickson committed
224
    expect(keyState.marker, equals('marked'));
225
  });
226

227
  testWidgets('Reparent during update children', (WidgetTester tester) async {
228
    final GlobalKey key = GlobalKey();
229

230
    await tester.pumpWidget(Stack(
231
      textDirection: TextDirection.ltr,
232
      children: <Widget>[
233 234
        StateMarker(key: key),
        Container(width: 100.0, height: 100.0),
235
      ],
236 237
    ));

238
    final StateMarkerState keyState = key.currentState as StateMarkerState;
Ian Hickson's avatar
Ian Hickson committed
239
    keyState.marker = 'marked';
240

241
    await tester.pumpWidget(Stack(
242
      textDirection: TextDirection.ltr,
243
      children: <Widget>[
244 245
        Container(width: 100.0, height: 100.0),
        StateMarker(key: key),
246
      ],
247 248 249
    ));

    expect(key.currentState, equals(keyState));
Ian Hickson's avatar
Ian Hickson committed
250
    expect(keyState.marker, equals('marked'));
251

252
    await tester.pumpWidget(Stack(
253
      textDirection: TextDirection.ltr,
254
      children: <Widget>[
255 256
        StateMarker(key: key),
        Container(width: 100.0, height: 100.0),
257
      ],
258 259 260
    ));

    expect(key.currentState, equals(keyState));
Ian Hickson's avatar
Ian Hickson committed
261
    expect(keyState.marker, equals('marked'));
262
  });
263

264
  testWidgets('Reparent to child during update children', (WidgetTester tester) async {
265
    final GlobalKey key = GlobalKey();
266

267
    await tester.pumpWidget(Stack(
268
      textDirection: TextDirection.ltr,
269
      children: <Widget>[
270 271 272
        Container(width: 100.0, height: 100.0),
        StateMarker(key: key),
        Container(width: 100.0, height: 100.0),
273
      ],
274 275
    ));

276
    final StateMarkerState keyState = key.currentState as StateMarkerState;
Ian Hickson's avatar
Ian Hickson committed
277
    keyState.marker = 'marked';
278

279
    await tester.pumpWidget(Stack(
280
      textDirection: TextDirection.ltr,
281
      children: <Widget>[
282 283
        Container(width: 100.0, height: 100.0, child: StateMarker(key: key)),
        Container(width: 100.0, height: 100.0),
284
      ],
285 286 287
    ));

    expect(key.currentState, equals(keyState));
Ian Hickson's avatar
Ian Hickson committed
288
    expect(keyState.marker, equals('marked'));
289

290
    await tester.pumpWidget(Stack(
291
      textDirection: TextDirection.ltr,
292
      children: <Widget>[
293 294 295
        Container(width: 100.0, height: 100.0),
        StateMarker(key: key),
        Container(width: 100.0, height: 100.0),
296
      ],
297 298 299
    ));

    expect(key.currentState, equals(keyState));
Ian Hickson's avatar
Ian Hickson committed
300
    expect(keyState.marker, equals('marked'));
301

302
    await tester.pumpWidget(Stack(
303
      textDirection: TextDirection.ltr,
304
      children: <Widget>[
305 306
        Container(width: 100.0, height: 100.0),
        Container(width: 100.0, height: 100.0, child: StateMarker(key: key)),
307
      ],
308 309 310
    ));

    expect(key.currentState, equals(keyState));
Ian Hickson's avatar
Ian Hickson committed
311
    expect(keyState.marker, equals('marked'));
312

313
    await tester.pumpWidget(Stack(
314
      textDirection: TextDirection.ltr,
315
      children: <Widget>[
316 317 318
        Container(width: 100.0, height: 100.0),
        StateMarker(key: key),
        Container(width: 100.0, height: 100.0),
319
      ],
320 321 322
    ));

    expect(key.currentState, equals(keyState));
Ian Hickson's avatar
Ian Hickson committed
323
    expect(keyState.marker, equals('marked'));
324
  });
325

326
  testWidgets('Deactivate implies build', (WidgetTester tester) async {
327
    final GlobalKey key = GlobalKey();
328
    final List<String> log = <String>[];
329
    final DeactivateLogger logger = DeactivateLogger(key: key, log: log);
330

331
    await tester.pumpWidget(
332
      Container(key: UniqueKey(), child: logger)
333
    );
334

335
    expect(log, equals(<String>['build']));
336

337
    await tester.pumpWidget(
338
      Container(key: UniqueKey(), child: logger)
339
    );
340

341
    expect(log, equals(<String>['build', 'deactivate', 'build']));
342
    log.clear();
343

344
    await tester.pump();
345
    expect(log, isEmpty);
346
  });
347 348

  testWidgets('Reparenting with multiple moves', (WidgetTester tester) async {
349 350 351
    final GlobalKey key1 = GlobalKey();
    final GlobalKey key2 = GlobalKey();
    final GlobalKey key3 = GlobalKey();
352 353

    await tester.pumpWidget(
354
      Row(
355
        textDirection: TextDirection.ltr,
356
        children: <Widget>[
357
          StateMarker(
358
            key: key1,
359
            child: StateMarker(
360
              key: key2,
361
              child: StateMarker(
362
                key: key3,
363 364 365 366 367
                child: StateMarker(child: Container(width: 100.0)),
              ),
            ),
          ),
        ],
368
      ),
369 370 371
    );

    await tester.pumpWidget(
372
      Row(
373
        textDirection: TextDirection.ltr,
374
        children: <Widget>[
375
          StateMarker(
376
            key: key2,
377
            child: StateMarker(child: Container(width: 100.0)),
378
          ),
379
          StateMarker(
380
            key: key1,
381
            child: StateMarker(
382
              key: key3,
383 384
              child: StateMarker(child: Container(width: 100.0)),
            ),
385
          ),
386
        ],
387
      ),
388 389
    );
  });
390
}