paginated_data_table_test.dart 8.77 KB
Newer Older
1 2 3 4 5 6
// Copyright 2017 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_test/flutter_test.dart';
7
import 'package:flutter/gestures.dart' show DragStartBehavior;
8

9
import 'data_table_test_utils.dart';
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24

class TestDataSource extends DataTableSource {
  int get generation => _generation;
  int _generation = 0;
  set generation(int value) {
    if (_generation == value)
      return;
    _generation = value;
    notifyListeners();
  }

  @override
  DataRow getRow(int index) {
    final Dessert dessert = kDesserts[index % kDesserts.length];
    final int page = index ~/ kDesserts.length;
25
    return DataRow.byIndex(
26 27
      index: index,
      cells: <DataCell>[
28 29 30
        DataCell(Text('${dessert.name} ($page)')),
        DataCell(Text('${dessert.calories}')),
        DataCell(Text('$generation')),
31 32 33 34 35
      ],
    );
  }

  @override
36
  int get rowCount => 50 * kDesserts.length;
37 38 39 40 41 42 43 44 45

  @override
  bool get isRowCountApproximate => false;

  @override
  int get selectedRowCount => 0;
}

void main() {
46
  testWidgets('PaginatedDataTable paging', (WidgetTester tester) async {
47
    final TestDataSource source = TestDataSource();
48

49
    final List<String> log = <String>[];
50

51 52
    await tester.pumpWidget(MaterialApp(
      home: PaginatedDataTable(
53
        header: const Text('Test table'),
54 55
        source: source,
        rowsPerPage: 2,
56
        availableRowsPerPage: const <int>[
57 58 59 60 61 62 63 64
          2, 4, 8, 16,
        ],
        onRowsPerPageChanged: (int rowsPerPage) {
          log.add('rows-per-page-changed: $rowsPerPage');
        },
        onPageChanged: (int rowIndex) {
          log.add('page-changed: $rowIndex');
        },
65
        columns: const <DataColumn>[
66 67 68
          DataColumn(label: Text('Name')),
          DataColumn(label: Text('Calories'), numeric: true),
          DataColumn(label: Text('Generation')),
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
        ],
      )
    ));

    await tester.tap(find.byTooltip('Next page'));

    expect(log, <String>['page-changed: 2']);
    log.clear();

    await tester.pump();

    expect(find.text('Frozen yogurt (0)'), findsNothing);
    expect(find.text('Eclair (0)'), findsOneWidget);
    expect(find.text('Gingerbread (0)'), findsNothing);

84
    await tester.tap(find.byIcon(Icons.chevron_left));
85 86 87 88 89 90 91 92 93 94

    expect(log, <String>['page-changed: 0']);
    log.clear();

    await tester.pump();

    expect(find.text('Frozen yogurt (0)'), findsOneWidget);
    expect(find.text('Eclair (0)'), findsNothing);
    expect(find.text('Gingerbread (0)'), findsNothing);

95
    await tester.tap(find.byIcon(Icons.chevron_left));
96 97 98 99

    expect(log, isEmpty);

    await tester.tap(find.text('2'));
100
    await tester.pumpAndSettle(const Duration(milliseconds: 200));
101 102

    await tester.tap(find.text('8').last);
103
    await tester.pumpAndSettle(const Duration(milliseconds: 200));
104 105 106 107 108

    expect(log, <String>['rows-per-page-changed: 8']);
    log.clear();
  });

109
  testWidgets('PaginatedDataTable control test', (WidgetTester tester) async {
110
    TestDataSource source = TestDataSource()
111 112
      ..generation = 42;

113
    final List<String> log = <String>[];
114 115

    Widget buildTable(TestDataSource source) {
116
      return PaginatedDataTable(
117
        header: const Text('Test table'),
118 119 120 121 122
        source: source,
        onPageChanged: (int rowIndex) {
          log.add('page-changed: $rowIndex');
        },
        columns: <DataColumn>[
123
          const DataColumn(
124
            label: Text('Name'),
125 126
            tooltip: 'Name',
          ),
127
          DataColumn(
128
            label: const Text('Calories'),
129 130 131 132 133 134
            tooltip: 'Calories',
            numeric: true,
            onSort: (int columnIndex, bool ascending) {
              log.add('column-sort: $columnIndex $ascending');
            }
          ),
135
          const DataColumn(
136
            label: Text('Generation'),
137 138 139 140
            tooltip: 'Generation',
          ),
        ],
        actions: <Widget>[
141
          IconButton(
142
            icon: const Icon(Icons.adjust),
143 144 145 146 147 148 149 150
            onPressed: () {
              log.add('action: adjust');
            },
          ),
        ],
      );
    }

151
    await tester.pumpWidget(MaterialApp(
152 153 154
      home: buildTable(source),
    ));

155
    // the column overflows because we're forcing it to 600 pixels high
156
    expect(tester.takeException(), contains('A RenderFlex overflowed by'));
157

158 159
    expect(find.text('Gingerbread (0)'), findsOneWidget);
    expect(find.text('Gingerbread (1)'), findsNothing);
160 161 162 163 164 165 166 167
    expect(find.text('42'), findsNWidgets(10));

    source.generation = 43;
    await tester.pump();

    expect(find.text('42'), findsNothing);
    expect(find.text('43'), findsNWidgets(10));

168
    source = TestDataSource()
169 170
      ..generation = 15;

171
    await tester.pumpWidget(MaterialApp(
172 173 174 175 176 177 178
      home: buildTable(source),
    ));

    expect(find.text('42'), findsNothing);
    expect(find.text('43'), findsNothing);
    expect(find.text('15'), findsNWidgets(10));

179
    final PaginatedDataTableState state = tester.state(find.byType(PaginatedDataTable));
180 181 182 183 184 185 186 187

    expect(log, isEmpty);
    state.pageTo(23);
    expect(log, <String>['page-changed: 20']);
    log.clear();

    await tester.pump();

188 189 190
    expect(find.text('Gingerbread (0)'), findsNothing);
    expect(find.text('Gingerbread (1)'), findsNothing);
    expect(find.text('Gingerbread (2)'), findsOneWidget);
191

192
    await tester.tap(find.byIcon(Icons.adjust));
193 194 195
    expect(log, <String>['action: adjust']);
    log.clear();
  });
196 197

  testWidgets('PaginatedDataTable text alignment', (WidgetTester tester) async {
198 199
    await tester.pumpWidget(MaterialApp(
      home: PaginatedDataTable(
200
        header: const Text('HEADER'),
201
        source: TestDataSource(),
202
        rowsPerPage: 8,
203
        availableRowsPerPage: const <int>[
204 205 206
          8, 9,
        ],
        onRowsPerPageChanged: (int rowsPerPage) { },
207
        columns: const <DataColumn>[
208 209 210
          DataColumn(label: Text('COL1')),
          DataColumn(label: Text('COL2')),
          DataColumn(label: Text('COL3')),
211 212 213 214 215 216 217 218 219
        ],
      ),
    ));
    expect(find.text('Rows per page:'), findsOneWidget);
    expect(find.text('8'), findsOneWidget);
    expect(tester.getTopRight(find.text('8')).dx, tester.getTopRight(find.text('Rows per page:')).dx + 40.0); // per spec
  });

  testWidgets('PaginatedDataTable with large text', (WidgetTester tester) async {
220 221 222
    final TestDataSource source = TestDataSource();
    await tester.pumpWidget(MaterialApp(
      home: MediaQuery(
223 224 225
        data: const MediaQueryData(
          textScaleFactor: 20.0,
        ),
226
        child: PaginatedDataTable(
227 228 229
          header: const Text('HEADER'),
          source: source,
          rowsPerPage: 501,
230
          availableRowsPerPage: const <int>[ 501 ],
231
          onRowsPerPageChanged: (int rowsPerPage) { },
232
          columns: const <DataColumn>[
233 234 235
            DataColumn(label: Text('COL1')),
            DataColumn(label: Text('COL2')),
            DataColumn(label: Text('COL3')),
236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
          ],
        ),
      ),
    ));
    // the column overflows because we're forcing it to 600 pixels high
    expect(tester.takeException(), contains('A RenderFlex overflowed by'));
    expect(find.text('Rows per page:'), findsOneWidget);
    // Test that we will show some options in the drop down even if the lowest option is bigger than the source:
    assert(501 > source.rowCount);
    expect(find.text('501'), findsOneWidget);
    // Test that it fits:
    expect(tester.getTopRight(find.text('501')).dx, greaterThanOrEqualTo(tester.getTopRight(find.text('Rows per page:')).dx + 40.0));
  });

  testWidgets('PaginatedDataTable footer scrolls', (WidgetTester tester) async {
251
    final TestDataSource source = TestDataSource();
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
    await tester.pumpWidget(
      MaterialApp(
        home: Align(
          alignment: Alignment.topLeft,
          child: SizedBox(
            width: 100.0,
            child: PaginatedDataTable(
              header: const Text('HEADER'),
              source: source,
              rowsPerPage: 5,
              dragStartBehavior: DragStartBehavior.down,
              availableRowsPerPage: const <int>[ 5 ],
              onRowsPerPageChanged: (int rowsPerPage) { },
              columns: const <DataColumn>[
                DataColumn(label: Text('COL1')),
                DataColumn(label: Text('COL2')),
                DataColumn(label: Text('COL3')),
              ],
            ),
271 272 273
          ),
        ),
      ),
274
    );
275 276 277
    expect(find.text('Rows per page:'), findsOneWidget);
    expect(tester.getTopLeft(find.text('Rows per page:')).dx, lessThan(0.0)); // off screen
    await tester.dragFrom(
278
      Offset(50.0, tester.getTopLeft(find.text('Rows per page:')).dy),
279 280 281 282 283 284
      const Offset(1000.0, 0.0),
    );
    await tester.pump();
    expect(find.text('Rows per page:'), findsOneWidget);
    expect(tester.getTopLeft(find.text('Rows per page:')).dx, 18.0); // 14 padding in the footer row, 4 padding from the card
  });
285
}