@@ -60,7 +60,8 @@ void testMain() {
6060 value: 'hi' ,
6161 isFocused: true ,
6262 );
63- final SemanticTextField textField = textFieldSemantics.semanticRole! as SemanticTextField ;
63+ final SemanticTextField textField =
64+ textFieldSemantics.semanticRole! as SemanticTextField ;
6465
6566 // ensureInitialized() isn't called prior to calling dispose() here.
6667 // Since we are conditionally calling dispose() on our
@@ -92,41 +93,53 @@ void testMain() {
9293 test ('renders a text field' , () {
9394 createTextFieldSemantics (value: 'hello' );
9495
95- expectSemanticsTree (owner (), '''
96- <sem>
97- < input />
98- </sem>''' );
96+ expectSemanticsTree (
97+ owner (),
98+ '<sem>< input type="text" /></sem>' ,
99+ );
99100
100101 // TODO(yjbanov): this used to attempt to test that value="hello" but the
101102 // test was a false positive. We should revise this test and
102103 // make sure it tests the right things:
103104 // https://github.com/flutter/flutter/issues/147200
104- final SemanticsObject node = owner ().debugSemanticsTree! [0 ]! ;
105- final SemanticTextField textFieldRole = node.semanticRole! as SemanticTextField ;
106- final DomHTMLInputElement inputElement =
107- textFieldRole.editableElement as DomHTMLInputElement ;
105+ final node = owner ().debugSemanticsTree! [0 ]! ;
106+ final textFieldRole = node.semanticRole! as SemanticTextField ;
107+ final inputElement = textFieldRole.editableElement as DomHTMLInputElement ;
108108 expect (inputElement.tagName.toLowerCase (), 'input' );
109109 expect (inputElement.value, '' );
110110 expect (inputElement.disabled, isFalse);
111111 });
112112
113+ test ('renders a password field' , () {
114+ createTextFieldSemantics (value: 'secret' , isObscured: true );
115+
116+ expectSemanticsTree (
117+ owner (),
118+ '<sem><input type="password" /></sem>' ,
119+ );
120+
121+ final node = owner ().debugSemanticsTree! [0 ]! ;
122+ final textFieldRole = node.semanticRole! as SemanticTextField ;
123+ final inputElement = textFieldRole.editableElement as DomHTMLInputElement ;
124+ expect (inputElement.disabled, isFalse);
125+ });
126+
113127 test ('renders a disabled text field' , () {
114128 createTextFieldSemantics (isEnabled: false , value: 'hello' );
115129 expectSemanticsTree (owner (), '''<sem><input /></sem>''' );
116- final SemanticsObject node = owner ().debugSemanticsTree! [0 ]! ;
117- final SemanticTextField textFieldRole = node.semanticRole! as SemanticTextField ;
118- final DomHTMLInputElement inputElement =
119- textFieldRole.editableElement as DomHTMLInputElement ;
130+ final node = owner ().debugSemanticsTree! [0 ]! ;
131+ final textFieldRole = node.semanticRole! as SemanticTextField ;
132+ final inputElement = textFieldRole.editableElement as DomHTMLInputElement ;
120133 expect (inputElement.tagName.toLowerCase (), 'input' );
121134 expect (inputElement.disabled, isTrue);
122135 });
123136
124137 test ('sends a SemanticsAction.focus action when browser requests focus' ,
125138 () async {
126- final SemanticsActionLogger logger = SemanticsActionLogger ();
139+ final logger = SemanticsActionLogger ();
127140 createTextFieldSemantics (value: 'hello' );
128141
129- final DomElement textField = owner ()
142+ final textField = owner ()
130143 .semanticsHost
131144 .querySelector ('input[data-semantics-role="text-field"]' )! ;
132145
@@ -163,14 +176,14 @@ void testMain() {
163176 );
164177
165178 // Create
166- final SemanticsObject textFieldSemantics = createTextFieldSemantics (
179+ final textFieldSemantics = createTextFieldSemantics (
167180 value: 'hello' ,
168181 label: 'greeting' ,
169182 isFocused: true ,
170183 rect: const ui.Rect .fromLTWH (0 , 0 , 10 , 15 ),
171184 );
172185
173- final SemanticTextField textField = textFieldSemantics.semanticRole! as SemanticTextField ;
186+ final textField = textFieldSemantics.semanticRole! as SemanticTextField ;
174187 expect (owner ().semanticsHost.ownerDocument? .activeElement,
175188 strategy.domElement);
176189 expect (textField.editableElement, strategy.domElement);
@@ -231,16 +244,16 @@ void testMain() {
231244 onAction: (_) {},
232245 );
233246
234- final SemanticsObject textFieldSemantics = createTextFieldSemantics (
235- value: 'hello' ,
236- textSelectionBase: 1 ,
237- textSelectionExtent: 3 ,
238- isFocused: true ,
239- rect: const ui.Rect .fromLTWH (0 , 0 , 10 , 15 ));
247+ final textFieldSemantics = createTextFieldSemantics (
248+ value: 'hello' ,
249+ textSelectionBase: 1 ,
250+ textSelectionExtent: 3 ,
251+ isFocused: true ,
252+ rect: const ui.Rect .fromLTWH (0 , 0 , 10 , 15 ),
253+ );
240254
241- final SemanticTextField textField = textFieldSemantics.semanticRole! as SemanticTextField ;
242- final DomHTMLInputElement editableElement =
243- textField.editableElement as DomHTMLInputElement ;
255+ final textField = textFieldSemantics.semanticRole! as SemanticTextField ;
256+ final editableElement = textField.editableElement as DomHTMLInputElement ;
244257
245258 expect (editableElement, strategy.domElement);
246259 expect (editableElement.value, '' );
@@ -262,16 +275,16 @@ void testMain() {
262275 onAction: (_) {},
263276 );
264277
265- final SemanticsObject textFieldSemantics = createTextFieldSemantics (
266- value: 'hello' ,
267- textSelectionBase: 1 ,
268- textSelectionExtent: 3 ,
269- isFocused: true ,
270- rect: const ui.Rect .fromLTWH (0 , 0 , 10 , 15 ));
278+ final textFieldSemantics = createTextFieldSemantics (
279+ value: 'hello' ,
280+ textSelectionBase: 1 ,
281+ textSelectionExtent: 3 ,
282+ isFocused: true ,
283+ rect: const ui.Rect .fromLTWH (0 , 0 , 10 , 15 ),
284+ );
271285
272- final SemanticTextField textField = textFieldSemantics.semanticRole! as SemanticTextField ;
273- final DomHTMLInputElement editableElement =
274- textField.editableElement as DomHTMLInputElement ;
286+ final textField = textFieldSemantics.semanticRole! as SemanticTextField ;
287+ final editableElement = textField.editableElement as DomHTMLInputElement ;
275288
276289 // No updates expected on semantic updates
277290 expect (editableElement, strategy.domElement);
@@ -280,7 +293,7 @@ void testMain() {
280293 expect (editableElement.selectionEnd, 0 );
281294
282295 // Update from framework
283- const MethodCall setEditingState =
296+ const setEditingState =
284297 MethodCall ('TextInput.setEditingState' , < String , dynamic > {
285298 'text' : 'updated' ,
286299 'selectionBase' : 2 ,
@@ -306,12 +319,12 @@ void testMain() {
306319 onChange: (_, __) {},
307320 onAction: (_) {},
308321 );
309- final SemanticsObject textFieldSemantics = createTextFieldSemantics (
322+ final textFieldSemantics = createTextFieldSemantics (
310323 value: 'hello' ,
311324 isFocused: true ,
312325 );
313326
314- final SemanticTextField textField = textFieldSemantics.semanticRole! as SemanticTextField ;
327+ final textField = textFieldSemantics.semanticRole! as SemanticTextField ;
315328 expect (textField.editableElement, strategy.domElement);
316329 expect (owner ().semanticsHost.ownerDocument? .activeElement,
317330 strategy.domElement);
@@ -335,7 +348,7 @@ void testMain() {
335348 expect (strategy.domElement, isNull);
336349
337350 // During the semantics update the DOM element is created and is focused on.
338- final SemanticsObject textFieldSemantics = createTextFieldSemantics (
351+ final textFieldSemantics = createTextFieldSemantics (
339352 value: 'hello' ,
340353 isFocused: true ,
341354 );
@@ -347,7 +360,7 @@ void testMain() {
347360 expect (strategy.domElement, isNull);
348361
349362 // It doesn't remove the DOM element.
350- final SemanticTextField textField = textFieldSemantics.semanticRole! as SemanticTextField ;
363+ final textField = textFieldSemantics.semanticRole! as SemanticTextField ;
351364 expect (owner ().semanticsHost.contains (textField.editableElement), isTrue);
352365 // Editing element is not enabled.
353366 expect (strategy.isEnabled, isFalse);
@@ -412,8 +425,11 @@ void testMain() {
412425 isMultiline: true ,
413426 );
414427
415- final DomHTMLTextAreaElement textArea =
416- strategy.domElement! as DomHTMLTextAreaElement ;
428+ final textArea = strategy.domElement! as DomHTMLTextAreaElement ;
429+ expect (
430+ textArea.style.getPropertyValue ('-webkit-text-security' ),
431+ '' ,
432+ );
417433
418434 expect (owner ().semanticsHost.ownerDocument? .activeElement,
419435 strategy.domElement);
@@ -435,6 +451,27 @@ void testMain() {
435451 expect (strategy.isEnabled, isFalse);
436452 });
437453
454+ test ('multi-line and obscured' , () {
455+ strategy.enable (
456+ multilineConfig,
457+ onChange: (_, __) {},
458+ onAction: (_) {},
459+ );
460+ createTextFieldSemantics (
461+ value: 'hello' ,
462+ isFocused: true ,
463+ isMultiline: true ,
464+ isObscured: true ,
465+ );
466+
467+ expectSemanticsTree (
468+ owner (),
469+ '<sem><textarea style="-webkit-text-security: circle"></textarea></sem>' ,
470+ );
471+
472+ strategy.disable ();
473+ });
474+
438475 test ('Does not position or size its DOM element' , () {
439476 strategy.enable (
440477 singlelineConfig,
@@ -444,7 +481,7 @@ void testMain() {
444481
445482 // Send width and height that are different from semantics values on
446483 // purpose.
447- final EditableTextGeometry geometry = EditableTextGeometry (
484+ final geometry = EditableTextGeometry (
448485 height: 12 ,
449486 width: 13 ,
450487 globalTransform: Matrix4 .translationValues (14 , 15 , 0 ).storage,
@@ -534,11 +571,12 @@ SemanticsObject createTextFieldSemantics({
534571 bool isEnabled = true ,
535572 bool isFocused = false ,
536573 bool isMultiline = false ,
574+ bool isObscured = false ,
537575 ui.Rect rect = const ui.Rect .fromLTRB (0 , 0 , 100 , 50 ),
538576 int textSelectionBase = 0 ,
539577 int textSelectionExtent = 0 ,
540578}) {
541- final SemanticsTester tester = SemanticsTester (owner ());
579+ final tester = SemanticsTester (owner ());
542580 tester.updateNode (
543581 id: 0 ,
544582 isEnabled: isEnabled,
@@ -547,6 +585,7 @@ SemanticsObject createTextFieldSemantics({
547585 isTextField: true ,
548586 isFocused: isFocused,
549587 isMultiline: isMultiline,
588+ isObscured: isObscured,
550589 hasTap: true ,
551590 rect: rect,
552591 textDirection: ui.TextDirection .ltr,
0 commit comments