From 99790cc8c044c40c698e92a568f1ae1246d88963 Mon Sep 17 00:00:00 2001 From: chunhtai <47866232+chunhtai@users.noreply.github.com> Date: Wed, 16 Aug 2023 09:44:11 -0700 Subject: [PATCH] Add more use cases to a11y assessments (#132325) see [go/flutter-gar-reporting-q3-2023](http://go/flutter-gar-reporting-q3-2023) --- .../lib/use_cases/date_picker.dart | 51 ++++++++++++++++ .../lib/use_cases/dialog.dart | 59 +++++++++++++++++++ .../lib/use_cases/slider.dart | 53 +++++++++++++++++ .../lib/use_cases/text_field.dart | 42 +++++++++++++ .../lib/use_cases/text_field_disabled.dart | 44 ++++++++++++++ .../lib/use_cases/text_field_password.dart | 42 +++++++++++++ .../lib/use_cases/use_cases.dart | 12 ++++ .../test/date_picker_test.dart | 20 +++++++ dev/a11y_assessments/test/dialog_test.dart | 23 ++++++++ dev/a11y_assessments/test/slider_test.dart | 22 +++++++ dev/a11y_assessments/test/test_utils.dart | 17 ++++++ .../test/text_field_disabled_test.dart | 23 ++++++++ .../test/text_field_password_test.dart | 22 +++++++ .../test/text_field_test.dart | 22 +++++++ 14 files changed, 452 insertions(+) create mode 100644 dev/a11y_assessments/lib/use_cases/date_picker.dart create mode 100644 dev/a11y_assessments/lib/use_cases/dialog.dart create mode 100644 dev/a11y_assessments/lib/use_cases/slider.dart create mode 100644 dev/a11y_assessments/lib/use_cases/text_field.dart create mode 100644 dev/a11y_assessments/lib/use_cases/text_field_disabled.dart create mode 100644 dev/a11y_assessments/lib/use_cases/text_field_password.dart create mode 100644 dev/a11y_assessments/test/date_picker_test.dart create mode 100644 dev/a11y_assessments/test/dialog_test.dart create mode 100644 dev/a11y_assessments/test/slider_test.dart create mode 100644 dev/a11y_assessments/test/test_utils.dart create mode 100644 dev/a11y_assessments/test/text_field_disabled_test.dart create mode 100644 dev/a11y_assessments/test/text_field_password_test.dart create mode 100644 dev/a11y_assessments/test/text_field_test.dart diff --git a/dev/a11y_assessments/lib/use_cases/date_picker.dart b/dev/a11y_assessments/lib/use_cases/date_picker.dart new file mode 100644 index 0000000000..0a6b1e8556 --- /dev/null +++ b/dev/a11y_assessments/lib/use_cases/date_picker.dart @@ -0,0 +1,51 @@ +// Copyright 2014 The Flutter 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 'use_cases.dart'; + +class DatePickerUseCase extends UseCase { + + @override + String get name => 'DatePicker'; + + @override + String get route => '/date-picker'; + + @override + Widget build(BuildContext context) => const _MainWidget(); +} + +class _MainWidget extends StatefulWidget { + const _MainWidget(); + + @override + State<_MainWidget> createState() => _MainWidgetState(); +} + +class _MainWidgetState extends State<_MainWidget> { + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + backgroundColor: Theme.of(context).colorScheme.inversePrimary, + title: const Text('DatePicker'), + ), + body: Center( + child: TextButton( + onPressed: () => showDatePicker( + context: context, + initialEntryMode: DatePickerEntryMode.calendarOnly, + initialDate: DateTime.now(), + firstDate: DateTime.now().subtract(const Duration(days: 365)), + lastDate: DateTime.now().add(const Duration(days: 365)), + ), + child: const Text('Show Date Picker'), + ), + ), + ); + } +} diff --git a/dev/a11y_assessments/lib/use_cases/dialog.dart b/dev/a11y_assessments/lib/use_cases/dialog.dart new file mode 100644 index 0000000000..73ebddc5a9 --- /dev/null +++ b/dev/a11y_assessments/lib/use_cases/dialog.dart @@ -0,0 +1,59 @@ +// Copyright 2014 The Flutter 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 'use_cases.dart'; + +class DialogUseCase extends UseCase { + + @override + String get name => 'Dialog'; + + @override + String get route => '/dialog'; + + @override + Widget build(BuildContext context) => const _MainWidget(); +} + +class _MainWidget extends StatelessWidget { + const _MainWidget(); + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + backgroundColor: Theme.of(context).colorScheme.inversePrimary, + title: const Text('Dialog'), + ), + body: Center( + child: TextButton( + onPressed: () => showDialog( + context: context, + builder: (BuildContext context) => Dialog( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text('This is a typical dialog.'), + const SizedBox(height: 15), + TextButton( + onPressed: () { + Navigator.pop(context); + }, + child: const Text('Close'), + ), + ], + ), + ), + ), + ), + child: const Text('Show Dialog'), + ), + ), + ); + } +} diff --git a/dev/a11y_assessments/lib/use_cases/slider.dart b/dev/a11y_assessments/lib/use_cases/slider.dart new file mode 100644 index 0000000000..a83261dbea --- /dev/null +++ b/dev/a11y_assessments/lib/use_cases/slider.dart @@ -0,0 +1,53 @@ +// Copyright 2014 The Flutter 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 'use_cases.dart'; + +class SliderUseCase extends UseCase { + + @override + String get name => 'Slider'; + + @override + String get route => '/slider'; + + @override + Widget build(BuildContext context) => const MainWidget(); +} + +class MainWidget extends StatefulWidget { + const MainWidget({super.key}); + + @override + State createState() => MainWidgetState(); +} + +class MainWidgetState extends State { + double currentSliderValue = 20; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + backgroundColor: Theme.of(context).colorScheme.inversePrimary, + title: const Text('Slider'), + ), + body: Center( + child: Slider( + value: currentSliderValue, + max: 100, + divisions: 5, + label: currentSliderValue.round().toString(), + onChanged: (double value) { + setState(() { + currentSliderValue = value; + }); + }, + ), + ), + ); + } +} diff --git a/dev/a11y_assessments/lib/use_cases/text_field.dart b/dev/a11y_assessments/lib/use_cases/text_field.dart new file mode 100644 index 0000000000..3dd7e6eb16 --- /dev/null +++ b/dev/a11y_assessments/lib/use_cases/text_field.dart @@ -0,0 +1,42 @@ +// Copyright 2014 The Flutter 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 'use_cases.dart'; + +class TextFieldUseCase extends UseCase { + + @override + String get name => 'TextField'; + + @override + String get route => '/text-field'; + + @override + Widget build(BuildContext context) => const _MainWidget(); +} + +class _MainWidget extends StatelessWidget { + const _MainWidget(); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + backgroundColor: Theme.of(context).colorScheme.inversePrimary, + title: const Text('TextField'), + ), + body: const Center( + child: TextField( + decoration: InputDecoration( + labelText: 'Email', + suffixText: '@gmail.com', + hintText: 'Enter your email', + ), + ) + ), + ); + } +} diff --git a/dev/a11y_assessments/lib/use_cases/text_field_disabled.dart b/dev/a11y_assessments/lib/use_cases/text_field_disabled.dart new file mode 100644 index 0000000000..dcd2081800 --- /dev/null +++ b/dev/a11y_assessments/lib/use_cases/text_field_disabled.dart @@ -0,0 +1,44 @@ +// Copyright 2014 The Flutter 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 'use_cases.dart'; + +class TextFieldDisabledUseCase extends UseCase { + + @override + String get name => 'TextField disabled'; + + @override + String get route => '/text-field-disabled'; + + @override + Widget build(BuildContext context) => const _MainWidget(); +} + +class _MainWidget extends StatelessWidget { + const _MainWidget(); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + backgroundColor: Theme.of(context).colorScheme.inversePrimary, + title: const Text('TextField disabled'), + ), + body: Center( + child: TextField( + decoration: const InputDecoration( + labelText: 'Email', + suffixText: '@gmail.com', + hintText: 'Enter your email', + enabled: false, + ), + controller: TextEditingController(text: 'abc'), + ) + ), + ); + } +} diff --git a/dev/a11y_assessments/lib/use_cases/text_field_password.dart b/dev/a11y_assessments/lib/use_cases/text_field_password.dart new file mode 100644 index 0000000000..5da9337cb6 --- /dev/null +++ b/dev/a11y_assessments/lib/use_cases/text_field_password.dart @@ -0,0 +1,42 @@ +// Copyright 2014 The Flutter 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 'use_cases.dart'; + +class TextFieldPasswordUseCase extends UseCase { + + @override + String get name => 'TextField password'; + + @override + String get route => '/text-field-password'; + + @override + Widget build(BuildContext context) => const _MainWidget(); +} + +class _MainWidget extends StatelessWidget { + const _MainWidget(); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + backgroundColor: Theme.of(context).colorScheme.inversePrimary, + title: const Text('TextField password'), + ), + body: const Center( + child: TextField( + decoration: InputDecoration( + labelText: 'Password', + hintText: 'Enter your password', + ), + obscureText: true, + ) + ), + ); + } +} diff --git a/dev/a11y_assessments/lib/use_cases/use_cases.dart b/dev/a11y_assessments/lib/use_cases/use_cases.dart index 139109fa64..6099b87bc4 100644 --- a/dev/a11y_assessments/lib/use_cases/use_cases.dart +++ b/dev/a11y_assessments/lib/use_cases/use_cases.dart @@ -6,6 +6,12 @@ import 'package:flutter/widgets.dart'; import 'check_box_list_tile.dart'; import 'check_box_list_tile_disabled.dart'; +import 'date_picker.dart'; +import 'dialog.dart'; +import 'slider.dart'; +import 'text_field.dart'; +import 'text_field_disabled.dart'; +import 'text_field_password.dart'; abstract class UseCase { String get name; @@ -16,4 +22,10 @@ abstract class UseCase { final List useCases = [ CheckBoxListTile(), CheckBoxListTileDisabled(), + DialogUseCase(), + SliderUseCase(), + TextFieldUseCase(), + TextFieldDisabledUseCase(), + TextFieldPasswordUseCase(), + DatePickerUseCase(), ]; diff --git a/dev/a11y_assessments/test/date_picker_test.dart b/dev/a11y_assessments/test/date_picker_test.dart new file mode 100644 index 0000000000..a72c0ed7fd --- /dev/null +++ b/dev/a11y_assessments/test/date_picker_test.dart @@ -0,0 +1,20 @@ +// Copyright 2014 The Flutter 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:a11y_assessments/use_cases/date_picker.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'test_utils.dart'; + +void main() { + testWidgets('date picker can run', (WidgetTester tester) async { + await pumpsUseCase(tester, DatePickerUseCase()); + expect(find.text('Show Date Picker'), findsOneWidget); + + await tester.tap(find.text('Show Date Picker')); + await tester.pumpAndSettle(); + expect(find.byType(DatePickerDialog), findsOneWidget); + }); +} diff --git a/dev/a11y_assessments/test/dialog_test.dart b/dev/a11y_assessments/test/dialog_test.dart new file mode 100644 index 0000000000..98d8c71bb7 --- /dev/null +++ b/dev/a11y_assessments/test/dialog_test.dart @@ -0,0 +1,23 @@ +// Copyright 2014 The Flutter 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:a11y_assessments/use_cases/dialog.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'test_utils.dart'; + +void main() { + testWidgets('dialog can run', (WidgetTester tester) async { + await pumpsUseCase(tester, DialogUseCase()); + expect(find.text('Show Dialog'), findsOneWidget); + + await tester.tap(find.text('Show Dialog')); + await tester.pumpAndSettle(); + expect(find.text('This is a typical dialog.'), findsOneWidget); + + await tester.tap(find.text('Close')); + await tester.pumpAndSettle(); + expect(find.text('Show Dialog'), findsOneWidget); + }); +} diff --git a/dev/a11y_assessments/test/slider_test.dart b/dev/a11y_assessments/test/slider_test.dart new file mode 100644 index 0000000000..a8769e844e --- /dev/null +++ b/dev/a11y_assessments/test/slider_test.dart @@ -0,0 +1,22 @@ +// Copyright 2014 The Flutter 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:a11y_assessments/use_cases/slider.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'test_utils.dart'; + +void main() { + testWidgets('slider can run', (WidgetTester tester) async { + await pumpsUseCase(tester, SliderUseCase()); + expect(find.byType(Slider), findsOneWidget); + + await tester.tapAt(tester.getCenter(find.byType(Slider))); + await tester.pumpAndSettle(); + + final MainWidgetState state = tester.state(find.byType(MainWidget)); + expect(state.currentSliderValue, 60); + }); +} diff --git a/dev/a11y_assessments/test/test_utils.dart b/dev/a11y_assessments/test/test_utils.dart new file mode 100644 index 0000000000..8b2ae281db --- /dev/null +++ b/dev/a11y_assessments/test/test_utils.dart @@ -0,0 +1,17 @@ +// Copyright 2014 The Flutter 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:a11y_assessments/use_cases/use_cases.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +Future pumpsUseCase(WidgetTester tester, UseCase useCase) async { + await tester.pumpWidget(MaterialApp( + home: Builder( + builder: (BuildContext context) { + return useCase.build(context); + }, + ), + )); +} diff --git a/dev/a11y_assessments/test/text_field_disabled_test.dart b/dev/a11y_assessments/test/text_field_disabled_test.dart new file mode 100644 index 0000000000..0a304b9ef5 --- /dev/null +++ b/dev/a11y_assessments/test/text_field_disabled_test.dart @@ -0,0 +1,23 @@ +// Copyright 2014 The Flutter 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:a11y_assessments/use_cases/text_field_disabled.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'test_utils.dart'; + +void main() { + testWidgets('text field disabled can run', (WidgetTester tester) async { + await pumpsUseCase(tester, TextFieldDisabledUseCase()); + expect(find.byType(TextField), findsOneWidget); + expect(find.text('abc'), findsOneWidget); + + await tester.tap(find.byType(TextField)); + await tester.pumpAndSettle(); + await tester.enterText(find.byType(TextField), 'bde'); + await tester.pumpAndSettle(); + expect(find.text('abc'), findsOneWidget); + }); +} diff --git a/dev/a11y_assessments/test/text_field_password_test.dart b/dev/a11y_assessments/test/text_field_password_test.dart new file mode 100644 index 0000000000..44a65a4e00 --- /dev/null +++ b/dev/a11y_assessments/test/text_field_password_test.dart @@ -0,0 +1,22 @@ +// Copyright 2014 The Flutter 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:a11y_assessments/use_cases/text_field_password.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'test_utils.dart'; + +void main() { + testWidgets('text field password can run', (WidgetTester tester) async { + await pumpsUseCase(tester, TextFieldPasswordUseCase()); + expect(find.byType(TextField), findsOneWidget); + + await tester.tap(find.byType(TextField)); + await tester.pumpAndSettle(); + await tester.enterText(find.byType(TextField), 'abc'); + await tester.pumpAndSettle(); + expect(find.text('abc'), findsOneWidget); + }); +} diff --git a/dev/a11y_assessments/test/text_field_test.dart b/dev/a11y_assessments/test/text_field_test.dart new file mode 100644 index 0000000000..7623876edd --- /dev/null +++ b/dev/a11y_assessments/test/text_field_test.dart @@ -0,0 +1,22 @@ +// Copyright 2014 The Flutter 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:a11y_assessments/use_cases/text_field.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'test_utils.dart'; + +void main() { + testWidgets('text field can run', (WidgetTester tester) async { + await pumpsUseCase(tester, TextFieldUseCase()); + expect(find.byType(TextField), findsOneWidget); + + await tester.tap(find.byType(TextField)); + await tester.pumpAndSettle(); + await tester.enterText(find.byType(TextField), 'abc'); + await tester.pumpAndSettle(); + expect(find.text('abc'), findsOneWidget); + }); +}