Assert when duplicated keys are introduced in subsequent build (#81850)

This commit is contained in:
Michael Goderbauer 2021-05-06 19:49:02 -07:00 committed by GitHub
parent 6849e4b7e9
commit 3ab799bbc9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 58 additions and 10 deletions

View file

@ -6304,6 +6304,7 @@ class MultiChildRenderObjectElement extends RenderObjectElement {
void update(MultiChildRenderObjectWidget newWidget) {
super.update(newWidget);
assert(widget == newWidget);
assert(!debugChildrenHaveDuplicateKeys(widget, widget.children));
_children = updateChildren(_children, widget.children, forgottenChildren: _forgottenChildren);
_forgottenChildren.clear();
}

View file

@ -512,11 +512,9 @@ void main() {
expect(
exception.toString(),
equalsIgnoringHashCodes(
'Multiple widgets used the same GlobalKey.\n'
'The key [GlobalKey#00000 problematic] was used by 2 widgets:\n'
' SizedBox-[GlobalKey#00000 problematic]\n'
' Placeholder-[GlobalKey#00000 problematic]\n'
'A GlobalKey can only be specified on one widget at a time in the widget tree.',
'Duplicate keys found.\n'
'If multiple keyed nodes exist as children of another node, they must have unique keys.\n'
'Stack(alignment: AlignmentDirectional.topStart, textDirection: ltr, fit: loose) has multiple children with key [GlobalKey#00000 problematic].'
),
);
});
@ -541,11 +539,9 @@ void main() {
expect(
exception.toString(),
equalsIgnoringHashCodes(
'Multiple widgets used the same GlobalKey.\n'
'The key [GlobalKey#00000 problematic] was used by 2 widgets:\n'
' Container-[GlobalKey#00000 problematic]\n'
' Placeholder-[GlobalKey#00000 problematic]\n'
'A GlobalKey can only be specified on one widget at a time in the widget tree.',
'Duplicate keys found.\n'
'If multiple keyed nodes exist as children of another node, they must have unique keys.\n'
'Stack(alignment: AlignmentDirectional.topStart, textDirection: ltr, fit: loose) has multiple children with key [GlobalKey#00000 problematic].'
),
);
});

View file

@ -58,6 +58,57 @@ void main() {
<String>['0', '6', '7', '8', '1', '2', '3', '4', '5'],
);
});
testWidgets('Building a new MultiChildRenderObjectElement with children having duplicated keys throws', (WidgetTester tester) async {
const ValueKey<int> duplicatedKey = ValueKey<int>(1);
await tester.pumpWidget(Column(
children: const <Widget>[
Text('Text 1', textDirection: TextDirection.ltr, key: duplicatedKey),
Text('Text 2', textDirection: TextDirection.ltr, key: duplicatedKey),
],
));
expect(
tester.takeException(),
isA<FlutterError>().having(
(FlutterError error) => error.message,
'error.message',
startsWith('Duplicate keys found.'),
),
);
});
testWidgets('Updating a MultiChildRenderObjectElement to have children with duplicated keys throws', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/81541
const ValueKey<int> key1 = ValueKey<int>(1);
const ValueKey<int> key2 = ValueKey<int>(2);
Future<void> _buildWithKey(Key key) {
return tester.pumpWidget(Column(
children: <Widget>[
const Text('Text 1', textDirection: TextDirection.ltr, key: key1),
Text('Text 2', textDirection: TextDirection.ltr, key: key),
],
));
}
// Initial build with two different keys.
await _buildWithKey(key2);
expect(tester.takeException(), isNull);
// Subsequent build with duplicated keys.
await _buildWithKey(key1);
expect(
tester.takeException(),
isA<FlutterError>().having(
(FlutterError error) => error.message,
'error.message',
startsWith('Duplicate keys found.'),
),
);
});
}
// Do not use tester.renderObjectList(find.byType(RenderParagraph). That returns