// 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/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; void main() { test('DataTableThemeData copyWith, ==, hashCode basics', () { expect(const DataTableThemeData(), const DataTableThemeData().copyWith()); expect(const DataTableThemeData().hashCode, const DataTableThemeData().copyWith().hashCode); }); test('DataTableThemeData defaults', () { const DataTableThemeData themeData = DataTableThemeData(); expect(themeData.decoration, null); expect(themeData.dataRowColor, null); expect(themeData.dataRowHeight, null); expect(themeData.dataTextStyle, null); expect(themeData.headingRowColor, null); expect(themeData.headingRowHeight, null); expect(themeData.headingTextStyle, null); expect(themeData.horizontalMargin, null); expect(themeData.columnSpacing, null); expect(themeData.dividerThickness, null); expect(themeData.checkboxHorizontalMargin, null); const DataTableTheme theme = DataTableTheme(data: DataTableThemeData(), child: SizedBox()); expect(theme.data.decoration, null); expect(theme.data.dataRowColor, null); expect(theme.data.dataRowHeight, null); expect(theme.data.dataTextStyle, null); expect(theme.data.headingRowColor, null); expect(theme.data.headingRowHeight, null); expect(theme.data.headingTextStyle, null); expect(theme.data.horizontalMargin, null); expect(theme.data.columnSpacing, null); expect(theme.data.dividerThickness, null); expect(theme.data.checkboxHorizontalMargin, null); }); testWidgets('Default DataTableThemeData debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const DataTableThemeData().debugFillProperties(builder); final List<String> description = builder.properties .where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info)) .map((DiagnosticsNode node) => node.toString()) .toList(); expect(description, <String>[]); }); testWidgets('DataTableThemeData implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); DataTableThemeData( decoration: const BoxDecoration(color: Color(0xfffffff0)), dataRowColor: MaterialStateProperty.resolveWith<Color>( (Set<MaterialState> states) => const Color(0xfffffff1), ), dataRowHeight: 51.0, dataTextStyle: const TextStyle(fontSize: 12.0), headingRowColor: MaterialStateProperty.resolveWith<Color>( (Set<MaterialState> states) => const Color(0xfffffff2), ), headingRowHeight: 52.0, headingTextStyle: const TextStyle(fontSize: 14.0), horizontalMargin: 3.0, columnSpacing: 4.0, dividerThickness: 5.0, checkboxHorizontalMargin: 6.0, ).debugFillProperties(builder); final List<String> description = builder.properties .where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info)) .map((DiagnosticsNode node) => node.toString()) .toList(); expect(description[0], 'decoration: BoxDecoration(color: Color(0xfffffff0))'); expect(description[1], "dataRowColor: Instance of '_MaterialStatePropertyWith<Color>'"); expect(description[2], 'dataRowHeight: 51.0'); expect(description[3], 'dataTextStyle: TextStyle(inherit: true, size: 12.0)'); expect(description[4], "headingRowColor: Instance of '_MaterialStatePropertyWith<Color>'"); expect(description[5], 'headingRowHeight: 52.0'); expect(description[6], 'headingTextStyle: TextStyle(inherit: true, size: 14.0)'); expect(description[7], 'horizontalMargin: 3.0'); expect(description[8], 'columnSpacing: 4.0'); expect(description[9], 'dividerThickness: 5.0'); expect(description[10], 'checkboxHorizontalMargin: 6.0'); }); testWidgets('DataTable is themeable', (WidgetTester tester) async { const BoxDecoration decoration = BoxDecoration(color: Color(0xfffffff0)); const MaterialStateProperty<Color> dataRowColor = MaterialStatePropertyAll<Color>(Color(0xfffffff1)); const double dataRowHeight = 51.0; const TextStyle dataTextStyle = TextStyle(fontSize: 12.5); const MaterialStateProperty<Color> headingRowColor = MaterialStatePropertyAll<Color>(Color(0xfffffff2)); const double headingRowHeight = 52.0; const TextStyle headingTextStyle = TextStyle(fontSize: 14.5); const double horizontalMargin = 3.0; const double columnSpacing = 4.0; const double dividerThickness = 5.0; await tester.pumpWidget( MaterialApp( theme: ThemeData( dataTableTheme: const DataTableThemeData( decoration: decoration, dataRowColor: dataRowColor, dataRowHeight: dataRowHeight, dataTextStyle: dataTextStyle, headingRowColor: headingRowColor, headingRowHeight: headingRowHeight, headingTextStyle: headingTextStyle, horizontalMargin: horizontalMargin, columnSpacing: columnSpacing, dividerThickness: dividerThickness, ), ), home: Scaffold( body: DataTable( sortColumnIndex: 0, columns: <DataColumn>[ DataColumn( label: const Text('A'), onSort: (int columnIndex, bool ascending) {}, ), const DataColumn(label: Text('B')), ], rows: const <DataRow>[ DataRow(cells: <DataCell>[ DataCell(Text('Data')), DataCell(Text('Data 2')), ]), ], ), ), ), ); final Finder tableContainerFinder = find.ancestor(of: find.byType(Table), matching: find.byType(Container)); expect(tester.widgetList<Container>(tableContainerFinder).first.decoration, decoration); final TextStyle dataRowTextStyle = tester.renderObject<RenderParagraph>(find.text('Data')).text.style!; expect(dataRowTextStyle.fontSize, dataTextStyle.fontSize); expect(_tableRowBoxDecoration(tester: tester, index: 1).color, dataRowColor.resolve(<MaterialState>{})); expect(_tableRowBoxDecoration(tester: tester, index: 1).border!.top.width, dividerThickness); expect(tester.getSize(_findFirstContainerFor('Data')).height, dataRowHeight); final TextStyle headingRowTextStyle = tester.renderObject<RenderParagraph>(find.text('A')).text.style!; expect(headingRowTextStyle.fontSize, headingTextStyle.fontSize); expect(_tableRowBoxDecoration(tester: tester, index: 0).color, headingRowColor.resolve(<MaterialState>{})); expect(tester.getSize(_findFirstContainerFor('A')).height, headingRowHeight); expect(tester.getTopLeft(find.text('A')).dx, horizontalMargin); expect(tester.getTopLeft(find.text('Data 2')).dx - tester.getTopRight(find.text('Data')).dx, columnSpacing); }); testWidgets('DataTable properties are taken over the theme values', (WidgetTester tester) async { const BoxDecoration themeDecoration = BoxDecoration(color: Color(0xfffffff1)); const MaterialStateProperty<Color> themeDataRowColor = MaterialStatePropertyAll<Color>(Color(0xfffffff0)); const double themeDataRowHeight = 50.0; const TextStyle themeDataTextStyle = TextStyle(fontSize: 11.5); const MaterialStateProperty<Color> themeHeadingRowColor = MaterialStatePropertyAll<Color>(Color(0xfffffff1)); const double themeHeadingRowHeight = 51.0; const TextStyle themeHeadingTextStyle = TextStyle(fontSize: 13.5); const double themeHorizontalMargin = 2.0; const double themeColumnSpacing = 3.0; const double themeDividerThickness = 4.0; const BoxDecoration decoration = BoxDecoration(color: Color(0xfffffff0)); const MaterialStateProperty<Color> dataRowColor = MaterialStatePropertyAll<Color>(Color(0xfffffff1)); const double dataRowHeight = 51.0; const TextStyle dataTextStyle = TextStyle(fontSize: 12.5); const MaterialStateProperty<Color> headingRowColor = MaterialStatePropertyAll<Color>(Color(0xfffffff2)); const double headingRowHeight = 52.0; const TextStyle headingTextStyle = TextStyle(fontSize: 14.5); const double horizontalMargin = 3.0; const double columnSpacing = 4.0; const double dividerThickness = 5.0; await tester.pumpWidget( MaterialApp( theme: ThemeData( dataTableTheme: const DataTableThemeData( decoration: themeDecoration, dataRowColor: themeDataRowColor, dataRowHeight: themeDataRowHeight, dataTextStyle: themeDataTextStyle, headingRowColor: themeHeadingRowColor, headingRowHeight: themeHeadingRowHeight, headingTextStyle: themeHeadingTextStyle, horizontalMargin: themeHorizontalMargin, columnSpacing: themeColumnSpacing, dividerThickness: themeDividerThickness, ), ), home: Scaffold( body: DataTable( decoration: decoration, dataRowColor: dataRowColor, dataRowHeight: dataRowHeight, dataTextStyle: dataTextStyle, headingRowColor: headingRowColor, headingRowHeight: headingRowHeight, headingTextStyle: headingTextStyle, horizontalMargin: horizontalMargin, columnSpacing: columnSpacing, dividerThickness: dividerThickness, sortColumnIndex: 0, columns: <DataColumn>[ DataColumn( label: const Text('A'), onSort: (int columnIndex, bool ascending) {}, ), const DataColumn(label: Text('B')), ], rows: const <DataRow>[ DataRow(cells: <DataCell>[ DataCell(Text('Data')), DataCell(Text('Data 2')), ]), ], ), ), ), ); final Finder tableContainerFinder = find.ancestor(of: find.byType(Table), matching: find.byType(Container)); expect(tester.widget<Container>(tableContainerFinder).decoration, decoration); final TextStyle dataRowTextStyle = tester.renderObject<RenderParagraph>(find.text('Data')).text.style!; expect(dataRowTextStyle.fontSize, dataTextStyle.fontSize); expect(_tableRowBoxDecoration(tester: tester, index: 1).color, dataRowColor.resolve(<MaterialState>{})); expect(_tableRowBoxDecoration(tester: tester, index: 1).border!.top.width, dividerThickness); expect(tester.getSize(_findFirstContainerFor('Data')).height, dataRowHeight); final TextStyle headingRowTextStyle = tester.renderObject<RenderParagraph>(find.text('A')).text.style!; expect(headingRowTextStyle.fontSize, headingTextStyle.fontSize); expect(_tableRowBoxDecoration(tester: tester, index: 0).color, headingRowColor.resolve(<MaterialState>{})); expect(tester.getSize(_findFirstContainerFor('A')).height, headingRowHeight); expect(tester.getTopLeft(find.text('A')).dx, horizontalMargin); expect(tester.getTopLeft(find.text('Data 2')).dx - tester.getTopRight(find.text('Data')).dx, columnSpacing); }); testWidgets('Local DataTableTheme can override global DataTableTheme', (WidgetTester tester) async { const BoxDecoration globalThemeDecoration = BoxDecoration(color: Color(0xfffffff1)); const MaterialStateProperty<Color> globalThemeDataRowColor = MaterialStatePropertyAll<Color>(Color(0xfffffff0)); const double globalThemeDataRowHeight = 50.0; const TextStyle globalThemeDataTextStyle = TextStyle(fontSize: 11.5); const MaterialStateProperty<Color> globalThemeHeadingRowColor = MaterialStatePropertyAll<Color>(Color(0xfffffff1)); const double globalThemeHeadingRowHeight = 51.0; const TextStyle globalThemeHeadingTextStyle = TextStyle(fontSize: 13.5); const double globalThemeHorizontalMargin = 2.0; const double globalThemeColumnSpacing = 3.0; const double globalThemeDividerThickness = 4.0; const BoxDecoration localThemeDecoration = BoxDecoration(color: Color(0xfffffff0)); const MaterialStateProperty<Color> localThemeDataRowColor = MaterialStatePropertyAll<Color>(Color(0xfffffff1)); const double localThemeDataRowHeight = 51.0; const TextStyle localThemeDataTextStyle = TextStyle(fontSize: 12.5); const MaterialStateProperty<Color> localThemeHeadingRowColor = MaterialStatePropertyAll<Color>(Color(0xfffffff2)); const double localThemeHeadingRowHeight = 52.0; const TextStyle localThemeHeadingTextStyle = TextStyle(fontSize: 14.5); const double localThemeHorizontalMargin = 3.0; const double localThemeColumnSpacing = 4.0; const double localThemeDividerThickness = 5.0; await tester.pumpWidget( MaterialApp( theme: ThemeData( dataTableTheme: const DataTableThemeData( decoration: globalThemeDecoration, dataRowColor: globalThemeDataRowColor, dataRowHeight: globalThemeDataRowHeight, dataTextStyle: globalThemeDataTextStyle, headingRowColor: globalThemeHeadingRowColor, headingRowHeight: globalThemeHeadingRowHeight, headingTextStyle: globalThemeHeadingTextStyle, horizontalMargin: globalThemeHorizontalMargin, columnSpacing: globalThemeColumnSpacing, dividerThickness: globalThemeDividerThickness, ), ), home: Scaffold( body: DataTableTheme( data: const DataTableThemeData( decoration: localThemeDecoration, dataRowColor: localThemeDataRowColor, dataRowHeight: localThemeDataRowHeight, dataTextStyle: localThemeDataTextStyle, headingRowColor: localThemeHeadingRowColor, headingRowHeight: localThemeHeadingRowHeight, headingTextStyle: localThemeHeadingTextStyle, horizontalMargin: localThemeHorizontalMargin, columnSpacing: localThemeColumnSpacing, dividerThickness: localThemeDividerThickness, ), child: DataTable( sortColumnIndex: 0, columns: <DataColumn>[ DataColumn( label: const Text('A'), onSort: (int columnIndex, bool ascending) {}, ), const DataColumn(label: Text('B')), ], rows: const <DataRow>[ DataRow(cells: <DataCell>[ DataCell(Text('Data')), DataCell(Text('Data 2')), ]), ], ), ), ), ), ); final Finder tableContainerFinder = find.ancestor(of: find.byType(Table), matching: find.byType(Container)); expect(tester.widgetList<Container>(tableContainerFinder).first.decoration, localThemeDecoration); final TextStyle dataRowTextStyle = tester.renderObject<RenderParagraph>(find.text('Data')).text.style!; expect(dataRowTextStyle.fontSize, localThemeDataTextStyle.fontSize); expect(_tableRowBoxDecoration(tester: tester, index: 1).color, localThemeDataRowColor.resolve(<MaterialState>{})); expect(_tableRowBoxDecoration(tester: tester, index: 1).border!.top.width, localThemeDividerThickness); expect(tester.getSize(_findFirstContainerFor('Data')).height, localThemeDataRowHeight); final TextStyle headingRowTextStyle = tester.renderObject<RenderParagraph>(find.text('A')).text.style!; expect(headingRowTextStyle.fontSize, localThemeHeadingTextStyle.fontSize); expect(_tableRowBoxDecoration(tester: tester, index: 0).color, localThemeHeadingRowColor.resolve(<MaterialState>{})); expect(tester.getSize(_findFirstContainerFor('A')).height, localThemeHeadingRowHeight); expect(tester.getTopLeft(find.text('A')).dx, localThemeHorizontalMargin); expect(tester.getTopLeft(find.text('Data 2')).dx - tester.getTopRight(find.text('Data')).dx, localThemeColumnSpacing); }); } BoxDecoration _tableRowBoxDecoration({required WidgetTester tester, required int index}) { final Table table = tester.widget(find.byType(Table)); final TableRow tableRow = table.children[index]; return tableRow.decoration! as BoxDecoration; } // The finder matches with the Container of the cell content, as well as the // Container wrapping the whole table. The first one is used to test row // heights. Finder _findFirstContainerFor(String text) => find.widgetWithText(Container, text).first;