// Copyright 2018 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. import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; import '../widgets/semantics_tester.dart'; void main() { testWidgets('SemanticsNodes overlapping in z', (WidgetTester tester) async { // Cards are semantic boundaries that always own their own SemanticNode, // PhysicalModels merge their semantics information into parent. // // Side view of the widget tree: // // Card('abs. elevation: 30') --------------- // | 8 ----------- Card('abs. elevation 25') // Card('abs. elevation: 22') --------------- | // | 7 | // PhysicalModel('abs. elevation: 15') --------------- | 15 // | 5 | // --------------------------------------- Card('abs. elevation: 10') // | 10 // | // --------------------------------------- 'ground' final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget(MaterialApp( home: Column( children: <Widget>[ const Text('ground'), Card( elevation: 10.0, child: Column( children: <Widget>[ const Text('absolute elevation: 10'), PhysicalModel( elevation: 5.0, color: Colors.black, child: Column( children: <Widget>[ const Text('absolute elevation: 15'), Card( elevation: 7.0, child: Column( children: const <Widget>[ Text('absolute elevation: 22'), Card( elevation: 8.0, child: Text('absolute elevation: 30'), ), ], ), ), ], ), ), const Card( elevation: 15.0, child: Text('absolute elevation: 25'), ), ], ), ), ], ), )); final SemanticsNode ground = tester.getSemantics(find.text('ground')); expect(ground.thickness, 0.0); expect(ground.elevation, 0.0); expect(ground.label, 'ground'); final SemanticsNode elevation10 = tester.getSemantics(find.text('absolute elevation: 10')); final SemanticsNode elevation15 = tester.getSemantics(find.text('absolute elevation: 15')); expect(elevation10, same(elevation15)); // configs got merged into each other. expect(elevation10.thickness, 15.0); expect(elevation10.elevation, 0.0); expect(elevation10.label, 'absolute elevation: 10\nabsolute elevation: 15'); final SemanticsNode elevation22 = tester.getSemantics(find.text('absolute elevation: 22')); expect(elevation22.thickness, 7.0); expect(elevation22.elevation, 15.0); expect(elevation22.label, 'absolute elevation: 22'); final SemanticsNode elevation25 = tester.getSemantics(find.text('absolute elevation: 25')); expect(elevation25.thickness, 15.0); expect(elevation25.elevation, 10.0); expect(elevation22.label, 'absolute elevation: 22'); final SemanticsNode elevation30 = tester.getSemantics(find.text('absolute elevation: 30')); expect(elevation30.thickness, 8.0); expect(elevation30.elevation, 7.0); expect(elevation30.label, 'absolute elevation: 30'); semantics.dispose(); }); testWidgets('SemanticsNodes overlapping in z with switched children', (WidgetTester tester) async { // Same as 'SemanticsNodes overlapping in z', but the order of children // is reversed final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget(MaterialApp( home: Column( children: <Widget>[ const Text('ground'), Card( elevation: 10.0, child: Column( children: <Widget>[ const Card( elevation: 15.0, child: Text('absolute elevation: 25'), ), PhysicalModel( elevation: 5.0, color: Colors.black, child: Column( children: <Widget>[ const Text('absolute elevation: 15'), Card( elevation: 7.0, child: Column( children: const <Widget>[ Text('absolute elevation: 22'), Card( elevation: 8.0, child: Text('absolute elevation: 30'), ), ], ), ), ], ), ), const Text('absolute elevation: 10'), ], ), ), ], ), )); final SemanticsNode ground = tester.getSemantics(find.text('ground')); expect(ground.thickness, 0.0); expect(ground.elevation, 0.0); expect(ground.label, 'ground'); final SemanticsNode elevation10 = tester.getSemantics(find.text('absolute elevation: 10')); final SemanticsNode elevation15 = tester.getSemantics(find.text('absolute elevation: 15')); expect(elevation10, same(elevation15)); // configs got merged into each other. expect(elevation10.thickness, 15.0); expect(elevation10.elevation, 0.0); expect(elevation10.label, 'absolute elevation: 15\nabsolute elevation: 10'); final SemanticsNode elevation22 = tester.getSemantics(find.text('absolute elevation: 22')); expect(elevation22.thickness, 7.0); expect(elevation22.elevation, 15.0); expect(elevation22.label, 'absolute elevation: 22'); final SemanticsNode elevation25 = tester.getSemantics(find.text('absolute elevation: 25')); expect(elevation25.thickness, 15.0); expect(elevation25.elevation, 10.0); expect(elevation22.label, 'absolute elevation: 22'); final SemanticsNode elevation30 = tester.getSemantics(find.text('absolute elevation: 30')); expect(elevation30.thickness, 8.0); expect(elevation30.elevation, 7.0); expect(elevation30.label, 'absolute elevation: 30'); semantics.dispose(); }); testWidgets('single node thickness', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget(const MaterialApp( home: Center( child: Material( elevation: 24.0, child: Text('Hello'), ), ), )); final SemanticsNode node = tester.getSemantics(find.text('Hello')); expect(node.thickness, 0.0); expect(node.elevation, 24.0); expect(node.label, 'Hello'); semantics.dispose(); }); testWidgets('force-merge', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget(MaterialApp( home: Card( elevation: 10.0, child: Column( children: <Widget>[ const Text('abs. elevation: 10.0'), MergeSemantics( child: Semantics( explicitChildNodes: true, // just to be sure that it's going to be an explicit merge child: Column( children: const <Widget>[ Card( elevation: 15.0, child: Text('abs. elevation 25.0'), ), Card( elevation: 5.0, child: Text('abs. elevation 15.0'), ), ], ), ), ), ], ), ), )); final SemanticsNode elevation10 = tester.getSemantics(find.text('abs. elevation: 10.0')); expect(elevation10.thickness, 10.0); expect(elevation10.elevation, 0.0); expect(elevation10.label, 'abs. elevation: 10.0'); expect(elevation10.childrenCount, 1); // TODO(goderbauer): remove awkward workaround when accessing force-merged // SemanticsData becomes easier, https://github.com/flutter/flutter/issues/25669 SemanticsData mergedChildData; elevation10.visitChildren((SemanticsNode child) { expect(mergedChildData, isNull); mergedChildData = child.getSemanticsData(); return true; }); expect(mergedChildData.thickness, 15.0); expect(mergedChildData.elevation, 10.0); expect(mergedChildData.label, 'abs. elevation 25.0\nabs. elevation 15.0'); semantics.dispose(); }); testWidgets('force-merge with inversed children', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget(MaterialApp( home: Card( elevation: 10.0, child: Column( children: <Widget>[ const Text('abs. elevation: 10.0'), MergeSemantics( child: Semantics( explicitChildNodes: true, // just to be sure that it's going to be an explicit merge child: Column( children: const <Widget>[ Card( elevation: 5.0, child: Text('abs. elevation 15.0'), ), Card( elevation: 15.0, child: Text('abs. elevation 25.0'), ), ], ), ), ), ], ), ), )); final SemanticsNode elevation10 = tester.getSemantics(find.text('abs. elevation: 10.0')); expect(elevation10.thickness, 10.0); expect(elevation10.elevation, 0.0); expect(elevation10.label, 'abs. elevation: 10.0'); expect(elevation10.childrenCount, 1); // TODO(goderbauer): remove awkward workaround when accessing force-merged // SemanticsData becomes easier, https://github.com/flutter/flutter/issues/25669 SemanticsData mergedChildData; elevation10.visitChildren((SemanticsNode child) { expect(mergedChildData, isNull); mergedChildData = child.getSemanticsData(); return true; }); expect(mergedChildData.thickness, 15.0); expect(mergedChildData.elevation, 10.0); expect(mergedChildData.label, 'abs. elevation 15.0\nabs. elevation 25.0'); semantics.dispose(); }); }