| // Copyright 2014 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import 'package:flutter/material.dart'; |
| import 'package:flutter_test/flutter_test.dart'; |
| |
| class TestWidget extends StatefulWidget { |
| const TestWidget({ |
| Key? key, |
| required this.child, |
| required this.persistentState, |
| required this.syncedState, |
| }) : super(key: key); |
| |
| final Widget child; |
| final int persistentState; |
| final int syncedState; |
| |
| @override |
| TestWidgetState createState() => TestWidgetState(); |
| } |
| |
| class TestWidgetState extends State<TestWidget> { |
| late int persistentState; |
| late int syncedState; |
| int updates = 0; |
| |
| @override |
| void initState() { |
| super.initState(); |
| persistentState = widget.persistentState; |
| syncedState = widget.syncedState; |
| } |
| |
| @override |
| void didUpdateWidget(TestWidget oldWidget) { |
| super.didUpdateWidget(oldWidget); |
| syncedState = widget.syncedState; |
| // we explicitly do NOT sync the persistentState from the new instance |
| // because we're using that to track whether we got recreated |
| updates += 1; |
| } |
| |
| @override |
| Widget build(BuildContext context) => widget.child; |
| } |
| |
| void main() { |
| |
| testWidgets('no change', (WidgetTester tester) async { |
| await tester.pumpWidget( |
| Container( |
| color: Colors.blue, |
| child: Container( |
| color: Colors.blue, |
| child: TestWidget( |
| persistentState: 1, |
| syncedState: 0, |
| child: Container(), |
| ), |
| ), |
| ), |
| ); |
| |
| final TestWidgetState state = tester.state(find.byType(TestWidget)); |
| |
| expect(state.persistentState, equals(1)); |
| expect(state.updates, equals(0)); |
| |
| await tester.pumpWidget( |
| Container( |
| color: Colors.blue, |
| child: Container( |
| color: Colors.blue, |
| child: TestWidget( |
| persistentState: 2, |
| syncedState: 0, |
| child: Container(), |
| ), |
| ), |
| ), |
| ); |
| |
| expect(state.persistentState, equals(1)); |
| expect(state.updates, equals(1)); |
| |
| await tester.pumpWidget(Container()); |
| }); |
| |
| testWidgets('remove one', (WidgetTester tester) async { |
| await tester.pumpWidget( |
| Container( |
| color: Colors.blue, |
| child: Container( |
| color: Colors.blue, |
| child: TestWidget( |
| persistentState: 10, |
| syncedState: 0, |
| child: Container(), |
| ), |
| ), |
| ), |
| ); |
| |
| TestWidgetState state = tester.state(find.byType(TestWidget)); |
| |
| expect(state.persistentState, equals(10)); |
| expect(state.updates, equals(0)); |
| |
| await tester.pumpWidget( |
| Container( |
| color: Colors.green, |
| child: TestWidget( |
| persistentState: 11, |
| syncedState: 0, |
| child: Container(), |
| ), |
| ), |
| ); |
| |
| state = tester.state(find.byType(TestWidget)); |
| |
| expect(state.persistentState, equals(11)); |
| expect(state.updates, equals(0)); |
| |
| await tester.pumpWidget(Container()); |
| }); |
| |
| testWidgets('swap instances around', (WidgetTester tester) async { |
| const Widget a = TestWidget(persistentState: 0x61, syncedState: 0x41, child: Text('apple', textDirection: TextDirection.ltr)); |
| const Widget b = TestWidget(persistentState: 0x62, syncedState: 0x42, child: Text('banana', textDirection: TextDirection.ltr)); |
| await tester.pumpWidget(Column()); |
| |
| final GlobalKey keyA = GlobalKey(); |
| final GlobalKey keyB = GlobalKey(); |
| |
| await tester.pumpWidget( |
| Column( |
| children: <Widget>[ |
| Container( |
| key: keyA, |
| child: a, |
| ), |
| Container( |
| key: keyB, |
| child: b, |
| ), |
| ], |
| ), |
| ); |
| |
| TestWidgetState first, second; |
| |
| first = tester.state(find.byWidget(a)); |
| second = tester.state(find.byWidget(b)); |
| |
| expect(first.widget, equals(a)); |
| expect(first.persistentState, equals(0x61)); |
| expect(first.syncedState, equals(0x41)); |
| expect(second.widget, equals(b)); |
| expect(second.persistentState, equals(0x62)); |
| expect(second.syncedState, equals(0x42)); |
| |
| await tester.pumpWidget( |
| Column( |
| children: <Widget>[ |
| Container( |
| key: keyA, |
| child: a, |
| ), |
| Container( |
| key: keyB, |
| child: b, |
| ), |
| ], |
| ), |
| ); |
| |
| first = tester.state(find.byWidget(a)); |
| second = tester.state(find.byWidget(b)); |
| |
| // same as before |
| expect(first.widget, equals(a)); |
| expect(first.persistentState, equals(0x61)); |
| expect(first.syncedState, equals(0x41)); |
| expect(second.widget, equals(b)); |
| expect(second.persistentState, equals(0x62)); |
| expect(second.syncedState, equals(0x42)); |
| |
| // now we swap the nodes over |
| // since they are both "old" nodes, they shouldn't sync with each other even though they look alike |
| |
| await tester.pumpWidget( |
| Column( |
| children: <Widget>[ |
| Container( |
| key: keyA, |
| child: b, |
| ), |
| Container( |
| key: keyB, |
| child: a, |
| ), |
| ], |
| ), |
| ); |
| |
| first = tester.state(find.byWidget(b)); |
| second = tester.state(find.byWidget(a)); |
| |
| expect(first.widget, equals(b)); |
| expect(first.persistentState, equals(0x61)); |
| expect(first.syncedState, equals(0x42)); |
| expect(second.widget, equals(a)); |
| expect(second.persistentState, equals(0x62)); |
| expect(second.syncedState, equals(0x41)); |
| }); |
| } |