From a3b384f6e9f2502c4980e44e8f9f70f2c3cddb01 Mon Sep 17 00:00:00 2001 From: Chun-Heng Tai Date: Tue, 27 Jun 2023 12:00:11 -0700 Subject: [PATCH 1/3] [web] TextField a11y focus should call didGain/didLose a11y focus action --- .../lib/src/engine/semantics/text_field.dart | 11 ++++- .../engine/semantics/text_field_test.dart | 48 +++++++++++++------ 2 files changed, 44 insertions(+), 15 deletions(-) diff --git a/lib/web_ui/lib/src/engine/semantics/text_field.dart b/lib/web_ui/lib/src/engine/semantics/text_field.dart index 5f89f88f2f217..9d6a88a9ccb46 100644 --- a/lib/web_ui/lib/src/engine/semantics/text_field.dart +++ b/lib/web_ui/lib/src/engine/semantics/text_field.dart @@ -301,7 +301,16 @@ class TextField extends PrimaryRoleManager { } EnginePlatformDispatcher.instance.invokeOnSemanticsAction( - semanticsObject.id, ui.SemanticsAction.tap, null); + semanticsObject.id, ui.SemanticsAction.didGainAccessibilityFocus, null); + })); + activeEditableElement.addEventListener('blur', + createDomEventListener((DomEvent event) { + if (semanticsObject.owner.gestureMode != GestureMode.browserGestures) { + return; + } + + EnginePlatformDispatcher.instance.invokeOnSemanticsAction( + semanticsObject.id, ui.SemanticsAction.didLoseAccessibilityFocus, null); })); } diff --git a/lib/web_ui/test/engine/semantics/text_field_test.dart b/lib/web_ui/test/engine/semantics/text_field_test.dart index 503f1cdd11bd9..edd1401a402d5 100644 --- a/lib/web_ui/test/engine/semantics/text_field_test.dart +++ b/lib/web_ui/test/engine/semantics/text_field_test.dart @@ -92,25 +92,45 @@ void testMain() { '''); }); - // TODO(yjbanov): this test will need to be adjusted for Safari when we add - // Safari testing. - test('sends a tap action when browser requests focus', () async { - final SemanticsActionLogger logger = SemanticsActionLogger(); - createTextFieldSemantics(value: 'hello'); + // TODO(yjbanov): this test will need to be adjusted for Safari when we add + // Safari testing. + test('sends a didGainAccessibilityFocus action when browser requests focus', () async { + final SemanticsActionLogger logger = SemanticsActionLogger(); + createTextFieldSemantics(value: 'hello'); - final DomElement textField = appHostNode - .querySelector('input[data-semantics-role="text-field"]')!; + final DomElement textField = appHostNode + .querySelector('input[data-semantics-role="text-field"]')!; - expect(appHostNode.ownerDocument?.activeElement, isNot(textField)); + expect(appHostNode.ownerDocument?.activeElement, isNot(textField)); - textField.focus(); + textField.focus(); - expect(appHostNode.ownerDocument?.activeElement, textField); - expect(await logger.idLog.first, 0); - expect(await logger.actionLog.first, ui.SemanticsAction.tap); + expect(appHostNode.ownerDocument?.activeElement, textField); + expect(await logger.idLog.first, 0); + expect(await logger.actionLog.first, ui.SemanticsAction.didGainAccessibilityFocus); + }, // TODO(yjbanov): https://github.com/flutter/flutter/issues/46638 + // TODO(yjbanov): https://github.com/flutter/flutter/issues/50590 + skip: browserEngine != BrowserEngine.blink); + + // TODO(yjbanov): this test will need to be adjusted for Safari when we add + // Safari testing. + test('sends a didLoseAccessibilityFocus action when browser requests focus', () async { + final SemanticsActionLogger logger = SemanticsActionLogger(); + createTextFieldSemantics(value: 'hello'); + + final DomElement textField = appHostNode + .querySelector('input[data-semantics-role="text-field"]')!; + + expect(appHostNode.ownerDocument?.activeElement, isNot(textField)); + + textField.blur(); + + expect(appHostNode.ownerDocument?.activeElement, textField); + expect(await logger.idLog.first, 0); + expect(await logger.actionLog.first, ui.SemanticsAction.didLoseAccessibilityFocus); }, // TODO(yjbanov): https://github.com/flutter/flutter/issues/46638 - // TODO(yjbanov): https://github.com/flutter/flutter/issues/50590 - skip: browserEngine != BrowserEngine.blink); + // TODO(yjbanov): https://github.com/flutter/flutter/issues/50590 + skip: browserEngine != BrowserEngine.blink); test('Syncs semantic state from framework', () { expect(appHostNode.ownerDocument?.activeElement, domDocument.body); From 737287547787767d8519d1b6297e343984bb825b Mon Sep 17 00:00:00 2001 From: Chun-Heng Tai Date: Fri, 30 Jun 2023 15:33:41 -0700 Subject: [PATCH 2/3] fix test --- lib/web_ui/test/engine/semantics/text_field_test.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/web_ui/test/engine/semantics/text_field_test.dart b/lib/web_ui/test/engine/semantics/text_field_test.dart index edd1401a402d5..8959a29b456fd 100644 --- a/lib/web_ui/test/engine/semantics/text_field_test.dart +++ b/lib/web_ui/test/engine/semantics/text_field_test.dart @@ -125,7 +125,6 @@ void testMain() { textField.blur(); - expect(appHostNode.ownerDocument?.activeElement, textField); expect(await logger.idLog.first, 0); expect(await logger.actionLog.first, ui.SemanticsAction.didLoseAccessibilityFocus); }, // TODO(yjbanov): https://github.com/flutter/flutter/issues/46638 From a12bfbc648d4878f0a5e93c93e6448db844ff0fe Mon Sep 17 00:00:00 2001 From: Chun-Heng Tai Date: Wed, 12 Jul 2023 13:53:13 -0700 Subject: [PATCH 3/3] fix test --- .../test/engine/semantics/semantics_test.dart | 6 +++--- .../test/engine/semantics/text_field_test.dart | 17 ++--------------- 2 files changed, 5 insertions(+), 18 deletions(-) diff --git a/lib/web_ui/test/engine/semantics/semantics_test.dart b/lib/web_ui/test/engine/semantics/semantics_test.dart index 5013ff3decc28..03a030358a74c 100644 --- a/lib/web_ui/test/engine/semantics/semantics_test.dart +++ b/lib/web_ui/test/engine/semantics/semantics_test.dart @@ -1517,7 +1517,7 @@ void _testTextField() { // TODO(yjbanov): this test will need to be adjusted for Safari when we add // Safari testing. - test('sends a tap action when text field is activated', () async { + test('sends a focus action when text field is activated', () async { final SemanticsActionLogger logger = SemanticsActionLogger(); semantics() ..debugOverrideTimestampFunction(() => _testTime) @@ -1526,7 +1526,7 @@ void _testTextField() { final ui.SemanticsUpdateBuilder builder = ui.SemanticsUpdateBuilder(); updateNode( builder, - actions: 0 | ui.SemanticsAction.tap.index, + actions: 0 | ui.SemanticsAction.didGainAccessibilityFocus.index, flags: 0 | ui.SemanticsFlag.isTextField.index, value: 'hello', transform: Matrix4.identity().toFloat64(), @@ -1544,7 +1544,7 @@ void _testTextField() { expect(appHostNode.ownerDocument?.activeElement, textField); expect(await logger.idLog.first, 0); - expect(await logger.actionLog.first, ui.SemanticsAction.tap); + expect(await logger.actionLog.first, ui.SemanticsAction.didGainAccessibilityFocus); semantics().semanticsEnabled = false; }, // TODO(yjbanov): https://github.com/flutter/flutter/issues/46638 diff --git a/lib/web_ui/test/engine/semantics/text_field_test.dart b/lib/web_ui/test/engine/semantics/text_field_test.dart index 8959a29b456fd..197e2fe50644d 100644 --- a/lib/web_ui/test/engine/semantics/text_field_test.dart +++ b/lib/web_ui/test/engine/semantics/text_field_test.dart @@ -94,7 +94,7 @@ void testMain() { // TODO(yjbanov): this test will need to be adjusted for Safari when we add // Safari testing. - test('sends a didGainAccessibilityFocus action when browser requests focus', () async { + test('sends a didGainAccessibilityFocus/didLoseAccessibilityFocus action when browser requests focus/blur', () async { final SemanticsActionLogger logger = SemanticsActionLogger(); createTextFieldSemantics(value: 'hello'); @@ -108,23 +108,10 @@ void testMain() { expect(appHostNode.ownerDocument?.activeElement, textField); expect(await logger.idLog.first, 0); expect(await logger.actionLog.first, ui.SemanticsAction.didGainAccessibilityFocus); - }, // TODO(yjbanov): https://github.com/flutter/flutter/issues/46638 - // TODO(yjbanov): https://github.com/flutter/flutter/issues/50590 - skip: browserEngine != BrowserEngine.blink); - - // TODO(yjbanov): this test will need to be adjusted for Safari when we add - // Safari testing. - test('sends a didLoseAccessibilityFocus action when browser requests focus', () async { - final SemanticsActionLogger logger = SemanticsActionLogger(); - createTextFieldSemantics(value: 'hello'); - - final DomElement textField = appHostNode - .querySelector('input[data-semantics-role="text-field"]')!; - - expect(appHostNode.ownerDocument?.activeElement, isNot(textField)); textField.blur(); + expect(appHostNode.ownerDocument?.activeElement, isNot(textField)); expect(await logger.idLog.first, 0); expect(await logger.actionLog.first, ui.SemanticsAction.didLoseAccessibilityFocus); }, // TODO(yjbanov): https://github.com/flutter/flutter/issues/46638