slider_test.dart 14.8 KB
Newer Older
1 2 3 4
// Copyright 2016 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.

5 6
import 'dart:ui';

7
import 'package:flutter/material.dart';
8
import 'package:flutter/rendering.dart';
9 10 11
import 'package:flutter/scheduler.dart';
import 'package:flutter_test/flutter_test.dart';

12
import '../rendering/mock_canvas.dart';
13
import '../widgets/semantics_tester.dart';
14

15
void main() {
16
  testWidgets('Slider can move when tapped (LTR)', (WidgetTester tester) async {
17
    final Key sliderKey = new UniqueKey();
18
    double value = 0.0;
19

20
    await tester.pumpWidget(
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
      new Directionality(
        textDirection: TextDirection.ltr,
        child: new StatefulBuilder(
          builder: (BuildContext context, StateSetter setState) {
            return new Material(
              child: new Center(
                child: new Slider(
                  key: sliderKey,
                  value: value,
                  onChanged: (double newValue) {
                    setState(() {
                      value = newValue;
                    });
                  },
                ),
36
              ),
37 38 39
            );
          },
        ),
40
      ),
41
    );
42

43
    expect(value, equals(0.0));
44
    await tester.tap(find.byKey(sliderKey));
45
    expect(value, equals(0.5));
46
    await tester.pump(); // No animation should start.
47
    expect(SchedulerBinding.instance.transientCallbackCount, equals(0));
48 49 50 51 52 53 54 55 56

    final Offset topLeft = tester.getTopLeft(find.byKey(sliderKey));
    final Offset bottomRight = tester.getBottomRight(find.byKey(sliderKey));

    final Offset target = topLeft + (bottomRight - topLeft) / 4.0;
    await tester.tapAt(target);
    expect(value, closeTo(0.25, 0.05));
    await tester.pump(); // No animation should start.
    expect(SchedulerBinding.instance.transientCallbackCount, equals(0));
57 58
  });

59
  testWidgets('Slider can move when tapped (RTL)', (WidgetTester tester) async {
60
    final Key sliderKey = new UniqueKey();
61
    double value = 0.0;
62

63
    await tester.pumpWidget(
64 65 66 67 68 69
      new Directionality(
        textDirection: TextDirection.rtl,
        child: new StatefulBuilder(
          builder: (BuildContext context, StateSetter setState) {
            return new Material(
              child: new Center(
70 71 72 73 74 75 76 77 78
                child: new Slider(
                  key: sliderKey,
                  value: value,
                  onChanged: (double newValue) {
                    setState(() {
                      value = newValue;
                    });
                  },
                ),
79
              ),
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
            );
          },
        ),
      ),
    );

    expect(value, equals(0.0));
    await tester.tap(find.byKey(sliderKey));
    expect(value, equals(0.5));
    await tester.pump(); // No animation should start.
    expect(SchedulerBinding.instance.transientCallbackCount, equals(0));

    final Offset topLeft = tester.getTopLeft(find.byKey(sliderKey));
    final Offset bottomRight = tester.getBottomRight(find.byKey(sliderKey));

    final Offset target = topLeft + (bottomRight - topLeft) / 4.0;
    await tester.tapAt(target);
    expect(value, closeTo(0.75, 0.05));
    await tester.pump(); // No animation should start.
    expect(SchedulerBinding.instance.transientCallbackCount, equals(0));
  });

  testWidgets('Slider take on discrete values', (WidgetTester tester) async {
    final Key sliderKey = new UniqueKey();
    double value = 0.0;

    await tester.pumpWidget(
      new Directionality(
        textDirection: TextDirection.ltr,
        child: new StatefulBuilder(
          builder: (BuildContext context, StateSetter setState) {
            return new Material(
              child: new Center(
                child: new SizedBox(
                  width: 144.0 + 2 * 16.0, // _kPreferredTotalWidth
                  child: new Slider(
                    key: sliderKey,
                    min: 0.0,
                    max: 100.0,
                    divisions: 10,
                    value: value,
                    onChanged: (double newValue) {
                      setState(() {
                        value = newValue;
                      });
                    },
                  ),
                ),
              ),
            );
          },
        ),
132
      ),
133
    );
134

135
    expect(value, equals(0.0));
136
    await tester.tap(find.byKey(sliderKey));
137
    expect(value, equals(50.0));
138
    await tester.drag(find.byKey(sliderKey), const Offset(5.0, 0.0));
139
    expect(value, equals(50.0));
140
    await tester.drag(find.byKey(sliderKey), const Offset(40.0, 0.0));
141
    expect(value, equals(80.0));
142

143
    await tester.pump(); // Starts animation.
144
    expect(SchedulerBinding.instance.transientCallbackCount, greaterThan(0));
145 146 147 148
    await tester.pump(const Duration(milliseconds: 200));
    await tester.pump(const Duration(milliseconds: 200));
    await tester.pump(const Duration(milliseconds: 200));
    await tester.pump(const Duration(milliseconds: 200));
149 150
    // Animation complete.
    expect(SchedulerBinding.instance.transientCallbackCount, equals(0));
151
  });
152

153 154 155
  testWidgets('Slider can be given zero values',
      (WidgetTester tester) async {
    final List<double> log = <double>[];
156 157 158 159 160 161 162 163 164
    await tester.pumpWidget(new Directionality(
      textDirection: TextDirection.ltr,
      child: new Material(
        child: new Slider(
          value: 0.0,
          min: 0.0,
          max: 1.0,
          onChanged: (double newValue) { log.add(newValue); },
        ),
165 166 167 168 169 170 171
      ),
    ));

    await tester.tap(find.byType(Slider));
    expect(log, <double>[0.5]);
    log.clear();

172 173 174 175 176 177 178 179 180
    await tester.pumpWidget(new Directionality(
      textDirection: TextDirection.ltr,
      child: new Material(
        child: new Slider(
          value: 0.0,
          min: 0.0,
          max: 0.0,
          onChanged: (double newValue) { log.add(newValue); },
        ),
181 182 183 184 185 186 187
      ),
    ));

    await tester.tap(find.byType(Slider));
    expect(log, <double>[]);
    log.clear();
  });
188 189 190 191 192 193

  testWidgets('Slider has a customizable active color',
      (WidgetTester tester) async {
    final Color customColor = const Color(0xFF4CD964);
    final ThemeData theme = new ThemeData(platform: TargetPlatform.android);
    Widget buildApp(Color activeColor) {
194 195 196 197 198 199 200 201 202 203 204
      return new Directionality(
        textDirection: TextDirection.ltr,
        child: new Material(
          child: new Center(
            child: new Theme(
              data: theme,
              child: new Slider(
                value: 0.5,
                activeColor: activeColor,
                onChanged: (double newValue) {},
              ),
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
            ),
          ),
        ),
      );
    }

    await tester.pumpWidget(buildApp(null));

    final RenderBox sliderBox =
        tester.firstRenderObject<RenderBox>(find.byType(Slider));

    expect(sliderBox, paints..rect(color: theme.accentColor)..rect(color: theme.unselectedWidgetColor));
    expect(sliderBox, paints..circle(color: theme.accentColor));
    expect(sliderBox, isNot(paints..circle(color: customColor)));
    expect(sliderBox, isNot(paints..circle(color: theme.unselectedWidgetColor)));
    await tester.pumpWidget(buildApp(customColor));
    expect(sliderBox, paints..rect(color: customColor)..rect(color: theme.unselectedWidgetColor));
    expect(sliderBox, paints..circle(color: customColor));
    expect(sliderBox, isNot(paints..circle(color: theme.accentColor)));
    expect(sliderBox, isNot(paints..circle(color: theme.unselectedWidgetColor)));
  });

  testWidgets('Slider has a customizable inactive color',
      (WidgetTester tester) async {
    final Color customColor = const Color(0xFF4CD964);
    final ThemeData theme = new ThemeData(platform: TargetPlatform.android);
    Widget buildApp(Color inactiveColor) {
232 233 234 235 236 237 238 239 240 241 242
      return new Directionality(
      textDirection: TextDirection.ltr,
        child: new Material(
          child: new Center(
            child: new Theme(
              data: theme,
              child: new Slider(
                value: 0.5,
                inactiveColor: inactiveColor,
                onChanged: (double newValue) {},
              ),
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
            ),
          ),
        ),
      );
    }

    await tester.pumpWidget(buildApp(null));

    final RenderBox sliderBox =
        tester.firstRenderObject<RenderBox>(find.byType(Slider));

    expect(sliderBox, paints..rect(color: theme.accentColor)..rect(color: theme.unselectedWidgetColor));
    expect(sliderBox, paints..circle(color: theme.accentColor));
    await tester.pumpWidget(buildApp(customColor));
    expect(sliderBox, paints..rect(color: theme.accentColor)..rect(color: customColor));
    expect(sliderBox, paints..circle(color: theme.accentColor));
  });
260

261
  testWidgets('Slider can draw an open thumb at min (LTR)',
262 263
      (WidgetTester tester) async {
    Widget buildApp(bool thumbOpenAtMin) {
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301
      return new Directionality(
        textDirection: TextDirection.ltr,
        child: new Material(
          child: new Center(
            child: new Slider(
              value: 0.0,
              thumbOpenAtMin: thumbOpenAtMin,
              onChanged: (double newValue) {},
            ),
          ),
        ),
      );
    }

    await tester.pumpWidget(buildApp(false));

    final RenderBox sliderBox =
        tester.firstRenderObject<RenderBox>(find.byType(Slider));

    expect(sliderBox, paints..circle(style: PaintingStyle.fill));
    expect(sliderBox, isNot(paints..circle()..circle()));
    await tester.pumpWidget(buildApp(true));
    expect(sliderBox, paints..circle(style: PaintingStyle.stroke));
    expect(sliderBox, isNot(paints..circle()..circle()));
  });

  testWidgets('Slider can draw an open thumb at min (RTL)',
      (WidgetTester tester) async {
    Widget buildApp(bool thumbOpenAtMin) {
      return new Directionality(
        textDirection: TextDirection.rtl,
        child: new Material(
          child: new Center(
            child: new Slider(
              value: 0.0,
              thumbOpenAtMin: thumbOpenAtMin,
              onChanged: (double newValue) {},
            ),
302 303 304 305 306 307 308 309 310 311
          ),
        ),
      );
    }

    await tester.pumpWidget(buildApp(false));

    final RenderBox sliderBox =
        tester.firstRenderObject<RenderBox>(find.byType(Slider));

312 313
    expect(sliderBox, paints..circle(style: PaintingStyle.fill));
    expect(sliderBox, isNot(paints..circle()..circle()));
314
    await tester.pumpWidget(buildApp(true));
315 316
    expect(sliderBox, paints..circle(style: PaintingStyle.stroke));
    expect(sliderBox, isNot(paints..circle()..circle()));
317
  });
318 319 320 321

  testWidgets('Slider can tap in vertical scroller',
      (WidgetTester tester) async {
    double value = 0.0;
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
    await tester.pumpWidget(new Directionality(
      textDirection: TextDirection.ltr,
      child: new Material(
        child: new ListView(
          children: <Widget>[
            new Slider(
              value: value,
              onChanged: (double newValue) {
                value = newValue;
              },
            ),
            new Container(
              height: 2000.0,
            ),
          ],
        ),
      ),
    ));

    await tester.tap(find.byType(Slider));
    expect(value, equals(0.5));
  });

  testWidgets('Slider drags immediately (LTR)', (WidgetTester tester) async {
    double value = 0.0;
    await tester.pumpWidget(new Directionality(
      textDirection: TextDirection.ltr,
      child: new Material(
        child: new Center(
          child: new Slider(
352 353 354 355 356
            value: value,
            onChanged: (double newValue) {
              value = newValue;
            },
          ),
357
        ),
358 359 360
      ),
    ));

361 362 363
    final Offset center = tester.getCenter(find.byType(Slider));
    final TestGesture gesture = await tester.startGesture(center);

364
    expect(value, equals(0.5));
365 366 367 368 369 370

    await gesture.moveBy(const Offset(1.0, 0.0));

    expect(value, greaterThan(0.5));

    await gesture.up();
371 372
  });

373
  testWidgets('Slider drags immediately (RTL)', (WidgetTester tester) async {
374
    double value = 0.0;
375 376 377 378 379 380 381 382 383 384
    await tester.pumpWidget(new Directionality(
      textDirection: TextDirection.rtl,
      child: new Material(
        child: new Center(
          child: new Slider(
            value: value,
            onChanged: (double newValue) {
              value = newValue;
            },
          ),
385 386 387 388
        ),
      ),
    ));

389
    final Offset center = tester.getCenter(find.byType(Slider));
390
    final TestGesture gesture = await tester.startGesture(center);
391 392 393

    expect(value, equals(0.5));

394
    await gesture.moveBy(const Offset(1.0, 0.0));
395

396
    expect(value, lessThan(0.5));
397 398 399

    await gesture.up();
  });
400 401

  testWidgets('Slider sizing', (WidgetTester tester) async {
402 403 404 405 406 407 408 409
    await tester.pumpWidget(const Directionality(
      textDirection: TextDirection.ltr,
      child: const Material(
        child: const Center(
          child: const Slider(
            value: 0.5,
            onChanged: null,
          ),
410 411 412 413 414
        ),
      ),
    ));
    expect(tester.renderObject<RenderBox>(find.byType(Slider)).size, const Size(800.0, 600.0));

415 416 417 418 419 420 421 422 423
    await tester.pumpWidget(const Directionality(
      textDirection: TextDirection.ltr,
      child: const Material(
        child: const Center(
          child: const IntrinsicWidth(
            child: const Slider(
              value: 0.5,
              onChanged: null,
            ),
424 425 426 427 428 429
          ),
        ),
      ),
    ));
    expect(tester.renderObject<RenderBox>(find.byType(Slider)).size, const Size(144.0 + 2.0 * 16.0, 600.0));

430 431 432 433 434 435 436 437 438 439 440
    await tester.pumpWidget(const Directionality(
      textDirection: TextDirection.ltr,
      child: const Material(
        child: const Center(
          child: const OverflowBox(
            maxWidth: double.INFINITY,
            maxHeight: double.INFINITY,
            child: const Slider(
              value: 0.5,
              onChanged: null,
            ),
441 442 443 444 445 446
          ),
        ),
      ),
    ));
    expect(tester.renderObject<RenderBox>(find.byType(Slider)).size, const Size(144.0 + 2.0 * 16.0, 32.0));
  });
447 448 449 450

  testWidgets('Slider Semantics', (WidgetTester tester) async {
    final SemanticsTester semantics = new SemanticsTester(tester);

451 452 453
    await tester.pumpWidget(new Directionality(
      textDirection: TextDirection.ltr,
      child: new Material(
454 455 456 457 458
        child: new Slider(
          value: 0.5,
          onChanged: (double v) {},
        ),
      ),
459
    ));
460 461 462 463 464 465 466 467 468 469 470 471 472 473 474

    expect(semantics, hasSemantics(
      new TestSemantics.root(
          children: <TestSemantics>[
            new TestSemantics.rootChild(
              id: 1,
              actions: SemanticsAction.decrease.index | SemanticsAction.increase.index,
            ),
          ]
      ),
      ignoreRect: true,
      ignoreTransform: true,
    ));

    // Disable slider
475
    await tester.pumpWidget(const Directionality(
476
      textDirection: TextDirection.ltr,
477 478
      child: const Material(
        child: const Slider(
479 480 481 482
          value: 0.5,
          onChanged: null,
        ),
      ),
483
    ));
484 485 486 487 488 489 490 491 492

    expect(semantics, hasSemantics(
      new TestSemantics.root(),
      ignoreRect: true,
      ignoreTransform: true,
    ));

    semantics.dispose();
  });
493
}