reparent_state_test.dart 10.7 KB
Newer Older
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
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 15 16 17 18 19
  StateMarkerState createState() => new StateMarkerState();
}

class StateMarkerState extends State<StateMarker> {
  String marker;

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

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

  final List<String> log;

  @override
  DeactivateLoggerState createState() => new DeactivateLoggerState();
}

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 48 49 50
    return new Container();
  }
}

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

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

74
    final StateMarkerState leftState = left.currentState;
Ian Hickson's avatar
Ian Hickson committed
75
    leftState.marker = 'left';
76
    final StateMarkerState rightState = right.currentState;
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 = const StateMarker();
84
    await tester.pumpWidget(
85
      new Stack(
86
        textDirection: TextDirection.ltr,
87 88
        children: <Widget>[
          new Container(
89
            child: new StateMarker(
90 91
              key: right,
              child: newGrandchild
92
            )
93 94 95 96 97 98 99 100 101
          ),
          new Container(
            child: new StateMarker(key: left)
          ),
        ]
      )
    );

    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 115 116
      new Center(
        child: new Container(
          child: new StateMarker(
            key: left,
            child: new Container()
117 118
          )
        )
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 = new GlobalKey();
    final GlobalKey right = new GlobalKey();
130

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

145
    final StateMarkerState leftState = left.currentState;
Ian Hickson's avatar
Ian Hickson committed
146
    leftState.marker = 'left';
147
    final StateMarkerState rightState = right.currentState;
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 = const StateMarker();
155
    await tester.pumpWidget(
156
      new Stack(
157
        textDirection: TextDirection.ltr,
158
        children: <Widget>[
159 160 161 162 163
          new StateMarker(
            key: right,
            child: newGrandchild
          ),
          new StateMarker(key: left)
164
        ]
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 182 183 184 185 186 187
      new Center(
        child: new Container(
          child: new StateMarker(
            key: left,
            child: new Container()
          )
        )
      )
    );
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 = new GlobalKey();
196

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

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

202 203 204 205 206 207 208 209 210 211 212 213
    await tester.pumpWidget(
      new Directionality(
        textDirection: TextDirection.ltr,
        child: new ListView(
          itemExtent: 100.0,
          children: <Widget>[
            new Container(
              key: const Key('container'),
              height: 100.0,
              child: new StateMarker(key: key),
            ),
          ],
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(new 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 = new GlobalKey();
229

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

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

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

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

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

    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 = new GlobalKey();
266

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

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

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

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

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

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

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

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

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

    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 328 329
    final GlobalKey key = new GlobalKey();
    final List<String> log = <String>[];
    final DeactivateLogger logger = new DeactivateLogger(key: key, log: log);
330

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

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

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

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

344
    await tester.pump();
345
    expect(log, isEmpty);
346
  });
347 348 349 350 351 352 353 354

  testWidgets('Reparenting with multiple moves', (WidgetTester tester) async {
    final GlobalKey key1 = new GlobalKey();
    final GlobalKey key2 = new GlobalKey();
    final GlobalKey key3 = new GlobalKey();

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

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