opacity_test.dart 6.59 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5 6 7
// This file is run as part of a reduced test set in CI on Mac and Windows
// machines.
@Tags(<String>['reduced-test-set'])
8
library;
9

10
import 'package:flutter/material.dart';
11
import 'package:flutter/rendering.dart';
12
import 'package:flutter_test/flutter_test.dart';
13 14 15 16 17 18

import '../rendering/mock_canvas.dart';
import 'semantics_tester.dart';

void main() {
  testWidgets('Opacity', (WidgetTester tester) async {
19
    final SemanticsTester semantics = SemanticsTester(tester);
20 21 22 23 24

    // Opacity 1.0: Semantics and painting
    await tester.pumpWidget(
      const Opacity(
        opacity: 1.0,
25
        child: Text('a', textDirection: TextDirection.rtl),
26 27 28
      ),
    );
    expect(semantics, hasSemantics(
29
      TestSemantics.root(
30
        children: <TestSemantics>[
31
          TestSemantics.rootChild(
32
            id: 1,
Dan Field's avatar
Dan Field committed
33
            rect: const Rect.fromLTRB(0.0, 0.0, 800.0, 600.0),
34 35
            label: 'a',
            textDirection: TextDirection.rtl,
36
          ),
37 38 39 40 41 42 43 44 45
        ],
      ),
    ));
    expect(find.byType(Opacity), paints..paragraph());

    // Opacity 0.0: Nothing
    await tester.pumpWidget(
      const Opacity(
        opacity: 0.0,
46
        child: Text('a', textDirection: TextDirection.rtl),
47 48 49
      ),
    );
    expect(semantics, hasSemantics(
50
      TestSemantics.root(),
51 52 53 54 55 56 57 58
    ));
    expect(find.byType(Opacity), paintsNothing);

    // Opacity 0.0 with semantics: Just semantics
    await tester.pumpWidget(
      const Opacity(
        opacity: 0.0,
        alwaysIncludeSemantics: true,
59
        child: Text('a', textDirection: TextDirection.rtl),
60 61 62
      ),
    );
    expect(semantics, hasSemantics(
63
      TestSemantics.root(
64
        children: <TestSemantics>[
65
          TestSemantics.rootChild(
66
            id: 1,
Dan Field's avatar
Dan Field committed
67
            rect: const Rect.fromLTRB(0.0, 0.0, 800.0, 600.0),
68 69
            label: 'a',
            textDirection: TextDirection.rtl,
70
          ),
71 72 73 74 75 76 77 78 79
        ],
      ),
    ));
    expect(find.byType(Opacity), paintsNothing);

    // Opacity 0.0 without semantics: Nothing
    await tester.pumpWidget(
      const Opacity(
        opacity: 0.0,
80
        child: Text('a', textDirection: TextDirection.rtl),
81 82 83
      ),
    );
    expect(semantics, hasSemantics(
84
      TestSemantics.root(),
85 86 87 88 89 90 91
    ));
    expect(find.byType(Opacity), paintsNothing);

    // Opacity 0.1: Semantics and painting
    await tester.pumpWidget(
      const Opacity(
        opacity: 0.1,
92
        child: Text('a', textDirection: TextDirection.rtl),
93 94 95
      ),
    );
    expect(semantics, hasSemantics(
96
      TestSemantics.root(
97
        children: <TestSemantics>[
98
          TestSemantics.rootChild(
99
            id: 1,
Dan Field's avatar
Dan Field committed
100
            rect: const Rect.fromLTRB(0.0, 0.0, 800.0, 600.0),
101 102
            label: 'a',
            textDirection: TextDirection.rtl,
103
          ),
104 105 106 107 108 109 110 111 112
        ],
      ),
    ));
    expect(find.byType(Opacity), paints..paragraph());

    // Opacity 0.1 without semantics: Still has semantics and painting
    await tester.pumpWidget(
      const Opacity(
        opacity: 0.1,
113
        child: Text('a', textDirection: TextDirection.rtl),
114 115 116
      ),
    );
    expect(semantics, hasSemantics(
117
      TestSemantics.root(
118
        children: <TestSemantics>[
119
          TestSemantics.rootChild(
120
            id: 1,
Dan Field's avatar
Dan Field committed
121
            rect: const Rect.fromLTRB(0.0, 0.0, 800.0, 600.0),
122 123
            label: 'a',
            textDirection: TextDirection.rtl,
124
          ),
125 126 127 128 129 130 131 132 133 134
        ],
      ),
    ));
    expect(find.byType(Opacity), paints..paragraph());

    // Opacity 0.1 with semantics: Semantics and painting
    await tester.pumpWidget(
      const Opacity(
        opacity: 0.1,
        alwaysIncludeSemantics: true,
135
        child: Text('a', textDirection: TextDirection.rtl),
136 137 138
      ),
    );
    expect(semantics, hasSemantics(
139
      TestSemantics.root(
140
        children: <TestSemantics>[
141
          TestSemantics.rootChild(
142
            id: 1,
Dan Field's avatar
Dan Field committed
143
            rect: const Rect.fromLTRB(0.0, 0.0, 800.0, 600.0),
144 145
            label: 'a',
            textDirection: TextDirection.rtl,
146
          ),
147 148 149 150 151 152 153
        ],
      ),
    ));
    expect(find.byType(Opacity), paints..paragraph());

    semantics.dispose();
  });
154 155 156 157

  testWidgets('offset is correctly handled in Opacity', (WidgetTester tester) async {
    await tester.pumpWidget(
      MaterialApp(
158
        theme: ThemeData(useMaterial3: false),
159 160 161 162 163 164 165 166 167 168 169 170
        home: Scaffold(
          body: SingleChildScrollView(
            child: RepaintBoundary(
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.stretch,
                children: List<Widget>.generate(10, (int index) {
                  return Opacity(
                    opacity: 0.5,
                    child: Padding(
                      padding: const EdgeInsets.all(5.0),
                      child: Container(
                          color: Colors.blue,
171
                          height: 50,
172
                      ),
173
                    ),
174 175 176
                  );
                }),
              ),
177 178 179
            ),
          ),
        ),
180
      ),
181 182 183
    );
    await expectLater(
      find.byType(RepaintBoundary).first,
184
      matchesGoldenFile('opacity_test.offset.png'),
185
    );
186
  });
187 188 189 190 191 192 193 194

  testWidgets('empty opacity does not crash', (WidgetTester tester) async {
    await tester.pumpWidget(
      RepaintBoundary(child: Opacity(opacity: 0.5, child: Container())),
    );
    final Element element = find.byType(RepaintBoundary).first.evaluate().single;
    // The following line will send the layer to engine and cause crash if an
    // empty opacity layer is sent.
195
    final OffsetLayer offsetLayer = element.renderObject!.debugLayer! as OffsetLayer;
196
    await offsetLayer.toImage(const Rect.fromLTRB(0.0, 0.0, 1.0, 1.0));
197
  }, skip: isBrowser); // https://github.com/flutter/flutter/issues/49857
Dan Field's avatar
Dan Field committed
198 199 200 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

  testWidgets('Child shows up in the right spot when opacity is disabled', (WidgetTester tester) async {
    debugDisableOpacityLayers = true;
    final GlobalKey key = GlobalKey();
    await tester.pumpWidget(
      RepaintBoundary(
        key: key,
        child: Directionality(
          textDirection: TextDirection.ltr,
          child: Stack(
            children: <Widget>[
              Positioned(
                top: 40,
                left: 140,
                child: Opacity(
                  opacity: .5,
                  child: Container(height: 100, width: 100, color: Colors.red),
                ),
              ),
            ],
          ),
        ),
      ),
    );

    await expectLater(
      find.byKey(key),
      matchesGoldenFile('opacity_disabled_with_child.png'),
    );
    debugDisableOpacityLayers = false;
  });
229
}