Unverified Commit 7b9a1755 authored by Michael Goderbauer's avatar Michael Goderbauer Committed by GitHub

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

parent 2977d3db
...@@ -6304,6 +6304,7 @@ class MultiChildRenderObjectElement extends RenderObjectElement { ...@@ -6304,6 +6304,7 @@ class MultiChildRenderObjectElement extends RenderObjectElement {
void update(MultiChildRenderObjectWidget newWidget) { void update(MultiChildRenderObjectWidget newWidget) {
super.update(newWidget); super.update(newWidget);
assert(widget == newWidget); assert(widget == newWidget);
assert(!debugChildrenHaveDuplicateKeys(widget, widget.children));
_children = updateChildren(_children, widget.children, forgottenChildren: _forgottenChildren); _children = updateChildren(_children, widget.children, forgottenChildren: _forgottenChildren);
_forgottenChildren.clear(); _forgottenChildren.clear();
} }
......
...@@ -512,11 +512,9 @@ void main() { ...@@ -512,11 +512,9 @@ void main() {
expect( expect(
exception.toString(), exception.toString(),
equalsIgnoringHashCodes( equalsIgnoringHashCodes(
'Multiple widgets used the same GlobalKey.\n' 'Duplicate keys found.\n'
'The key [GlobalKey#00000 problematic] was used by 2 widgets:\n' 'If multiple keyed nodes exist as children of another node, they must have unique keys.\n'
' SizedBox-[GlobalKey#00000 problematic]\n' 'Stack(alignment: AlignmentDirectional.topStart, textDirection: ltr, fit: loose) has multiple children with key [GlobalKey#00000 problematic].'
' Placeholder-[GlobalKey#00000 problematic]\n'
'A GlobalKey can only be specified on one widget at a time in the widget tree.',
), ),
); );
}); });
...@@ -541,11 +539,9 @@ void main() { ...@@ -541,11 +539,9 @@ void main() {
expect( expect(
exception.toString(), exception.toString(),
equalsIgnoringHashCodes( equalsIgnoringHashCodes(
'Multiple widgets used the same GlobalKey.\n' 'Duplicate keys found.\n'
'The key [GlobalKey#00000 problematic] was used by 2 widgets:\n' 'If multiple keyed nodes exist as children of another node, they must have unique keys.\n'
' Container-[GlobalKey#00000 problematic]\n' 'Stack(alignment: AlignmentDirectional.topStart, textDirection: ltr, fit: loose) has multiple children with key [GlobalKey#00000 problematic].'
' Placeholder-[GlobalKey#00000 problematic]\n'
'A GlobalKey can only be specified on one widget at a time in the widget tree.',
), ),
); );
}); });
......
...@@ -58,6 +58,57 @@ void main() { ...@@ -58,6 +58,57 @@ void main() {
<String>['0', '6', '7', '8', '1', '2', '3', '4', '5'], <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 // Do not use tester.renderObjectList(find.byType(RenderParagraph). That returns
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment