166 lines
5.6 KiB
Dart
166 lines
5.6 KiB
Dart
|
|
// 功能描述:语音结果选区替换、重复中间结果、拒绝权限、离页取消与长度边界回归。
|
|||
|
|
// 版本:1.0.0。
|
|||
|
|
import 'dart:async';
|
|||
|
|
import 'package:flutter/material.dart';
|
|||
|
|
import 'package:flutter_test/flutter_test.dart';
|
|||
|
|
import 'package:user_app/data/services/repair_speech.dart';
|
|||
|
|
import 'package:user_app/ui/features/tickets/repair_speech_button.dart';
|
|||
|
|
|
|||
|
|
class _Speech implements RepairSpeech {
|
|||
|
|
bool available = true;
|
|||
|
|
int cancels = 0, starts = 0;
|
|||
|
|
Completer<bool>? pending;
|
|||
|
|
late void Function(String) words, error;
|
|||
|
|
late void Function() done;
|
|||
|
|
@override
|
|||
|
|
Future<bool> start({
|
|||
|
|
required void Function(String) onWords,
|
|||
|
|
required void Function(String) onError,
|
|||
|
|
required void Function() onDone,
|
|||
|
|
}) async {
|
|||
|
|
starts++;
|
|||
|
|
words = onWords;
|
|||
|
|
error = onError;
|
|||
|
|
done = onDone;
|
|||
|
|
return pending?.future ?? available;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@override
|
|||
|
|
Future<void> stop() async {
|
|||
|
|
done();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@override
|
|||
|
|
Future<void> cancel() async {
|
|||
|
|
cancels++;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void main() {
|
|||
|
|
testWidgets('权限弹窗不取消初始化,切后台立即取消', (tester) async {
|
|||
|
|
final speech = _Speech()..pending = Completer<bool>();
|
|||
|
|
final controller = TextEditingController(text: '保留');
|
|||
|
|
await tester.pumpWidget(
|
|||
|
|
MaterialApp(
|
|||
|
|
home: Scaffold(
|
|||
|
|
body: RepairSpeechButton(controller: controller, onBusy: (_) {}, speech: speech),
|
|||
|
|
),
|
|||
|
|
),
|
|||
|
|
);
|
|||
|
|
await tester.tap(find.text('语音输入'));
|
|||
|
|
await tester.pump();
|
|||
|
|
tester.binding.handleAppLifecycleStateChanged(AppLifecycleState.inactive);
|
|||
|
|
await tester.pump();
|
|||
|
|
expect(speech.cancels, 0);
|
|||
|
|
tester.binding.handleAppLifecycleStateChanged(AppLifecycleState.paused);
|
|||
|
|
await tester.pump();
|
|||
|
|
expect(speech.cancels, 1);
|
|||
|
|
speech.pending!.complete(true);
|
|||
|
|
speech.words('迟到');
|
|||
|
|
await tester.pump();
|
|||
|
|
expect(controller.text, '保留');
|
|||
|
|
tester.binding.handleAppLifecycleStateChanged(AppLifecycleState.resumed);
|
|||
|
|
await tester.pumpWidget(const SizedBox());
|
|||
|
|
controller.dispose();
|
|||
|
|
});
|
|||
|
|
testWidgets('选区替换和中间结果不重复追加,结束后可再次录入', (tester) async {
|
|||
|
|
final speech = _Speech(), controller = TextEditingController(text: '前旧后');
|
|||
|
|
controller.selection = const TextSelection(baseOffset: 1, extentOffset: 2);
|
|||
|
|
final busy = <bool>[];
|
|||
|
|
await tester.pumpWidget(
|
|||
|
|
MaterialApp(
|
|||
|
|
home: Scaffold(
|
|||
|
|
body: RepairSpeechButton(controller: controller, onBusy: busy.add, speech: speech),
|
|||
|
|
),
|
|||
|
|
),
|
|||
|
|
);
|
|||
|
|
await tester.tap(find.text('语音输入'));
|
|||
|
|
await tester.pump();
|
|||
|
|
speech.words('阀门');
|
|||
|
|
speech.words('阀门异响');
|
|||
|
|
await tester.pump();
|
|||
|
|
expect(controller.text, '前阀门异响后');
|
|||
|
|
await tester.tap(find.text('结束识别'));
|
|||
|
|
await tester.pump();
|
|||
|
|
speech.words('迟到结果');
|
|||
|
|
expect(controller.text, '前阀门异响后');
|
|||
|
|
expect(busy.last, false);
|
|||
|
|
await tester.tap(find.text('语音输入'));
|
|||
|
|
await tester.pump();
|
|||
|
|
speech.words('补充');
|
|||
|
|
speech.done();
|
|||
|
|
await tester.pump();
|
|||
|
|
expect(controller.text, '前阀门异响补充后');
|
|||
|
|
expect(speech.starts, 2);
|
|||
|
|
await tester.pumpWidget(const SizedBox());
|
|||
|
|
controller.dispose();
|
|||
|
|
});
|
|||
|
|
testWidgets('不可用和权限拒绝保留输入并解除忙碌', (tester) async {
|
|||
|
|
final speech = _Speech()..available = false, controller = TextEditingController(text: '已有内容');
|
|||
|
|
final busy = <bool>[];
|
|||
|
|
await tester.pumpWidget(
|
|||
|
|
MaterialApp(
|
|||
|
|
home: Scaffold(
|
|||
|
|
body: RepairSpeechButton(controller: controller, onBusy: busy.add, speech: speech),
|
|||
|
|
),
|
|||
|
|
),
|
|||
|
|
);
|
|||
|
|
await tester.tap(find.text('语音输入'));
|
|||
|
|
await tester.pump();
|
|||
|
|
expect(find.textContaining('无法使用语音识别'), findsOneWidget);
|
|||
|
|
expect(controller.text, '已有内容');
|
|||
|
|
expect(busy.last, false);
|
|||
|
|
speech.available = true;
|
|||
|
|
await tester.tap(find.text('语音输入'));
|
|||
|
|
await tester.pump();
|
|||
|
|
speech.error('error_permission');
|
|||
|
|
await tester.pump();
|
|||
|
|
expect(find.textContaining('未获得麦克风'), findsOneWidget);
|
|||
|
|
expect(controller.text, '已有内容');
|
|||
|
|
expect(busy.last, false);
|
|||
|
|
await tester.pumpWidget(const SizedBox());
|
|||
|
|
controller.dispose();
|
|||
|
|
});
|
|||
|
|
testWidgets('初始化中离页取消,迟到结果不改变文字', (tester) async {
|
|||
|
|
final speech = _Speech()..pending = Completer<bool>(),
|
|||
|
|
controller = TextEditingController(text: '保留');
|
|||
|
|
await tester.pumpWidget(
|
|||
|
|
MaterialApp(
|
|||
|
|
home: Scaffold(
|
|||
|
|
body: RepairSpeechButton(controller: controller, onBusy: (_) {}, speech: speech),
|
|||
|
|
),
|
|||
|
|
),
|
|||
|
|
);
|
|||
|
|
await tester.tap(find.text('语音输入'));
|
|||
|
|
await tester.pump();
|
|||
|
|
await tester.pumpWidget(const SizedBox());
|
|||
|
|
speech.pending!.complete(true);
|
|||
|
|
speech.words('迟到');
|
|||
|
|
await tester.pump();
|
|||
|
|
expect(speech.cancels, 1);
|
|||
|
|
expect(controller.text, '保留');
|
|||
|
|
expect(tester.takeException(), isNull);
|
|||
|
|
controller.dispose();
|
|||
|
|
});
|
|||
|
|
testWidgets('识别遵守2000字符上限,不截断表情字符', (tester) async {
|
|||
|
|
final speech = _Speech(),
|
|||
|
|
controller = TextEditingController(text: List.filled(1999, '字').join());
|
|||
|
|
await tester.pumpWidget(
|
|||
|
|
MaterialApp(
|
|||
|
|
home: Scaffold(
|
|||
|
|
body: RepairSpeechButton(controller: controller, onBusy: (_) {}, speech: speech),
|
|||
|
|
),
|
|||
|
|
),
|
|||
|
|
);
|
|||
|
|
await tester.tap(find.text('语音输入'));
|
|||
|
|
await tester.pump();
|
|||
|
|
speech.words('😀多余');
|
|||
|
|
speech.done();
|
|||
|
|
await tester.pump();
|
|||
|
|
expect(controller.text.characters.length, 2000);
|
|||
|
|
expect(controller.text.endsWith('😀'), true);
|
|||
|
|
await tester.pumpWidget(const SizedBox());
|
|||
|
|
controller.dispose();
|
|||
|
|
});
|
|||
|
|
}
|