data_table_theme_test.dart 16.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
// 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();
17
    expect(themeData.decoration, null);
18 19 20 21 22 23 24 25 26
    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);
27
    expect(themeData.checkboxHorizontalMargin, null);
28

29
    const DataTableTheme theme = DataTableTheme(data: DataTableThemeData(), child: SizedBox());
30
    expect(theme.data.decoration, null);
31 32 33 34 35 36 37 38 39
    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);
40
    expect(theme.data.checkboxHorizontalMargin, null);
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
  });

  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(
58
      decoration: const BoxDecoration(color: Color(0xfffffff0)),
59 60 61 62 63 64 65 66 67 68 69 70 71
      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,
72
      checkboxHorizontalMargin: 6.0,
73 74 75 76 77 78 79
    ).debugFillProperties(builder);

    final List<String> description = builder.properties
      .where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info))
      .map((DiagnosticsNode node) => node.toString())
      .toList();

80
    expect(description[0], 'decoration: BoxDecoration(color: Color(0xfffffff0))');
81
    expect(description[1], "dataRowColor: Instance of '_MaterialStatePropertyWith<Color>'");
82 83
    expect(description[2], 'dataRowHeight: 51.0');
    expect(description[3], 'dataTextStyle: TextStyle(inherit: true, size: 12.0)');
84
    expect(description[4], "headingRowColor: Instance of '_MaterialStatePropertyWith<Color>'");
85 86 87 88 89
    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');
90
    expect(description[10], 'checkboxHorizontalMargin: 6.0');
91 92 93
  });

  testWidgets('DataTable is themeable', (WidgetTester tester) async {
94
    const BoxDecoration decoration = BoxDecoration(color: Color(0xfffffff0));
95
    const MaterialStateProperty<Color> dataRowColor = MaterialStatePropertyAll<Color>(Color(0xfffffff1));
96 97
    const double dataRowHeight = 51.0;
    const TextStyle dataTextStyle = TextStyle(fontSize: 12.5);
98
    const MaterialStateProperty<Color> headingRowColor = MaterialStatePropertyAll<Color>(Color(0xfffffff2));
99 100 101 102 103 104 105 106 107
    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(
108
          dataTableTheme: const DataTableThemeData(
109
            decoration: decoration,
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
            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')),
              ]),
            ],
          ),
        ),
      ),
    );

142 143 144
    final Finder tableContainerFinder = find.ancestor(of: find.byType(Table), matching: find.byType(Container));
    expect(tester.widgetList<Container>(tableContainerFinder).first.decoration, decoration);

145
    final TextStyle dataRowTextStyle = tester.renderObject<RenderParagraph>(find.text('Data')).text.style!;
146 147
    expect(dataRowTextStyle.fontSize, dataTextStyle.fontSize);
    expect(_tableRowBoxDecoration(tester: tester, index: 1).color, dataRowColor.resolve(<MaterialState>{}));
148
    expect(_tableRowBoxDecoration(tester: tester, index: 1).border!.top.width, dividerThickness);
149
    expect(tester.getSize(_findFirstContainerFor('Data')).height, dataRowHeight);
150

151
    final TextStyle headingRowTextStyle = tester.renderObject<RenderParagraph>(find.text('A')).text.style!;
152 153 154
    expect(headingRowTextStyle.fontSize, headingTextStyle.fontSize);
    expect(_tableRowBoxDecoration(tester: tester, index: 0).color, headingRowColor.resolve(<MaterialState>{}));

155
    expect(tester.getSize(_findFirstContainerFor('A')).height, headingRowHeight);
156 157 158 159 160
    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 {
161
    const BoxDecoration themeDecoration = BoxDecoration(color: Color(0xfffffff1));
162
    const MaterialStateProperty<Color> themeDataRowColor = MaterialStatePropertyAll<Color>(Color(0xfffffff0));
163 164
    const double themeDataRowHeight = 50.0;
    const TextStyle themeDataTextStyle = TextStyle(fontSize: 11.5);
165
    const MaterialStateProperty<Color> themeHeadingRowColor = MaterialStatePropertyAll<Color>(Color(0xfffffff1));
166 167 168 169 170 171
    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;

172
    const BoxDecoration decoration = BoxDecoration(color: Color(0xfffffff0));
173
    const MaterialStateProperty<Color> dataRowColor = MaterialStatePropertyAll<Color>(Color(0xfffffff1));
174 175
    const double dataRowHeight = 51.0;
    const TextStyle dataTextStyle = TextStyle(fontSize: 12.5);
176
    const MaterialStateProperty<Color> headingRowColor = MaterialStatePropertyAll<Color>(Color(0xfffffff2));
177 178 179 180 181 182 183 184
    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(
185
          dataTableTheme: const DataTableThemeData(
186
            decoration: themeDecoration,
187 188 189 190 191 192 193 194 195 196 197 198 199
            dataRowColor: themeDataRowColor,
            dataRowHeight: themeDataRowHeight,
            dataTextStyle: themeDataTextStyle,
            headingRowColor: themeHeadingRowColor,
            headingRowHeight: themeHeadingRowHeight,
            headingTextStyle: themeHeadingTextStyle,
            horizontalMargin: themeHorizontalMargin,
            columnSpacing: themeColumnSpacing,
            dividerThickness: themeDividerThickness,
          ),
        ),
        home: Scaffold(
          body: DataTable(
200
            decoration: decoration,
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
            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')),
              ]),
            ],
          ),
        ),
      ),
    );

229 230 231
    final Finder tableContainerFinder = find.ancestor(of: find.byType(Table), matching: find.byType(Container));
    expect(tester.widget<Container>(tableContainerFinder).decoration, decoration);

232
    final TextStyle dataRowTextStyle = tester.renderObject<RenderParagraph>(find.text('Data')).text.style!;
233 234
    expect(dataRowTextStyle.fontSize, dataTextStyle.fontSize);
    expect(_tableRowBoxDecoration(tester: tester, index: 1).color, dataRowColor.resolve(<MaterialState>{}));
235
    expect(_tableRowBoxDecoration(tester: tester, index: 1).border!.top.width, dividerThickness);
236
    expect(tester.getSize(_findFirstContainerFor('Data')).height, dataRowHeight);
237

238
    final TextStyle headingRowTextStyle = tester.renderObject<RenderParagraph>(find.text('A')).text.style!;
239 240 241
    expect(headingRowTextStyle.fontSize, headingTextStyle.fontSize);
    expect(_tableRowBoxDecoration(tester: tester, index: 0).color, headingRowColor.resolve(<MaterialState>{}));

242
    expect(tester.getSize(_findFirstContainerFor('A')).height, headingRowHeight);
243 244 245
    expect(tester.getTopLeft(find.text('A')).dx, horizontalMargin);
    expect(tester.getTopLeft(find.text('Data 2')).dx - tester.getTopRight(find.text('Data')).dx, columnSpacing);
  });
246 247

  testWidgets('Local DataTableTheme can override global DataTableTheme', (WidgetTester tester) async {
248
    const BoxDecoration globalThemeDecoration = BoxDecoration(color: Color(0xfffffff1));
249
    const MaterialStateProperty<Color> globalThemeDataRowColor = MaterialStatePropertyAll<Color>(Color(0xfffffff0));
250 251
    const double globalThemeDataRowHeight = 50.0;
    const TextStyle globalThemeDataTextStyle = TextStyle(fontSize: 11.5);
252
    const MaterialStateProperty<Color> globalThemeHeadingRowColor = MaterialStatePropertyAll<Color>(Color(0xfffffff1));
253 254 255 256 257
    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;
258 259

    const BoxDecoration localThemeDecoration = BoxDecoration(color: Color(0xfffffff0));
260
    const MaterialStateProperty<Color> localThemeDataRowColor = MaterialStatePropertyAll<Color>(Color(0xfffffff1));
261 262
    const double localThemeDataRowHeight = 51.0;
    const TextStyle localThemeDataTextStyle = TextStyle(fontSize: 12.5);
263
    const MaterialStateProperty<Color> localThemeHeadingRowColor = MaterialStatePropertyAll<Color>(Color(0xfffffff2));
264 265 266 267 268 269 270 271 272
    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(
273
          dataTableTheme: const DataTableThemeData(
274 275 276 277 278 279 280 281 282 283
            decoration: globalThemeDecoration,
            dataRowColor: globalThemeDataRowColor,
            dataRowHeight: globalThemeDataRowHeight,
            dataTextStyle: globalThemeDataTextStyle,
            headingRowColor: globalThemeHeadingRowColor,
            headingRowHeight: globalThemeHeadingRowHeight,
            headingTextStyle: globalThemeHeadingTextStyle,
            horizontalMargin: globalThemeHorizontalMargin,
            columnSpacing: globalThemeColumnSpacing,
            dividerThickness: globalThemeDividerThickness,
284 285 286 287
          ),
        ),
        home: Scaffold(
          body: DataTableTheme(
288
            data: const DataTableThemeData(
289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337
              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);
  });
338 339
}

340
BoxDecoration _tableRowBoxDecoration({required WidgetTester tester, required int index}) {
341 342
  final Table table = tester.widget(find.byType(Table));
  final TableRow tableRow = table.children[index];
343
  return tableRow.decoration! as BoxDecoration;
344
}
345 346 347 348 349

// 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;