@@ -2157,6 +2157,290 @@ void main() {
21572157 expect(state.textEditingValue.selection.isCollapsed, isTrue);
21582158 });
21592159
2160+ group('buttonItemsForToolbarOptions', () {
2161+ testWidgets('returns null when toolbarOptions are empty', (WidgetTester tester) async {
2162+ await tester.pumpWidget(
2163+ MaterialApp(
2164+ home: EditableText(
2165+ controller: TextEditingController(text: 'TEXT'),
2166+ toolbarOptions: ToolbarOptions.empty,
2167+ focusNode: focusNode,
2168+ style: textStyle,
2169+ cursorColor: cursorColor,
2170+ backgroundCursorColor: Colors.grey,
2171+ ),
2172+ ),
2173+ );
2174+
2175+ final EditableTextState state = tester.state<EditableTextState>(
2176+ find.byType(EditableText),
2177+ );
2178+
2179+ expect(state.buttonItemsForToolbarOptions(), isNull);
2180+ });
2181+
2182+ testWidgets('returns empty array when only cut is selected in toolbarOptions but cut is not enabled', (WidgetTester tester) async {
2183+ await tester.pumpWidget(
2184+ MaterialApp(
2185+ home: EditableText(
2186+ controller: TextEditingController(text: 'TEXT'),
2187+ toolbarOptions: const ToolbarOptions(cut: true),
2188+ readOnly: true,
2189+ focusNode: focusNode,
2190+ style: textStyle,
2191+ cursorColor: cursorColor,
2192+ backgroundCursorColor: Colors.grey,
2193+ ),
2194+ ),
2195+ );
2196+
2197+ final EditableTextState state = tester.state<EditableTextState>(
2198+ find.byType(EditableText),
2199+ );
2200+
2201+ expect(state.cutEnabled, isFalse);
2202+ expect(state.buttonItemsForToolbarOptions(), isEmpty);
2203+ });
2204+
2205+ testWidgets('returns only cut button when only cut is selected in toolbarOptions and cut is enabled', (WidgetTester tester) async {
2206+ const String text = 'TEXT';
2207+ final TextEditingController controller = TextEditingController(text: text);
2208+
2209+ await tester.pumpWidget(
2210+ MaterialApp(
2211+ home: EditableText(
2212+ controller: controller,
2213+ toolbarOptions: const ToolbarOptions(cut: true),
2214+ focusNode: focusNode,
2215+ style: textStyle,
2216+ cursorColor: cursorColor,
2217+ backgroundCursorColor: Colors.grey,
2218+ ),
2219+ ),
2220+ );
2221+
2222+ final EditableTextState state = tester.state<EditableTextState>(
2223+ find.byType(EditableText),
2224+ );
2225+
2226+ // Selecting all.
2227+ controller.selection = TextSelection(
2228+ baseOffset: 0,
2229+ extentOffset: controller.text.length,
2230+ );
2231+ expect(state.cutEnabled, isTrue);
2232+
2233+ final List<ContextMenuButtonItem>? items = state.buttonItemsForToolbarOptions();
2234+
2235+ expect(items, isNotNull);
2236+ expect(items, hasLength(1));
2237+
2238+ final ContextMenuButtonItem cutButton = items!.first;
2239+ expect(cutButton.type, ContextMenuButtonType.cut);
2240+
2241+ cutButton.onPressed();
2242+ await tester.pump();
2243+
2244+ expect(controller.text, isEmpty);
2245+ final ClipboardData? data = await Clipboard.getData('text/plain');
2246+ expect(data, isNotNull);
2247+ expect(data!.text, equals(text));
2248+ });
2249+
2250+ testWidgets('returns empty array when only copy is selected in toolbarOptions but copy is not enabled', (WidgetTester tester) async {
2251+ await tester.pumpWidget(
2252+ MaterialApp(
2253+ home: EditableText(
2254+ controller: TextEditingController(text: 'TEXT'),
2255+ toolbarOptions: const ToolbarOptions(copy: true),
2256+ obscureText: true,
2257+ focusNode: focusNode,
2258+ style: textStyle,
2259+ cursorColor: cursorColor,
2260+ backgroundCursorColor: Colors.grey,
2261+ ),
2262+ ),
2263+ );
2264+
2265+ final EditableTextState state = tester.state<EditableTextState>(
2266+ find.byType(EditableText),
2267+ );
2268+
2269+ expect(state.copyEnabled, isFalse);
2270+ expect(state.buttonItemsForToolbarOptions(), isEmpty);
2271+ });
2272+
2273+ testWidgets('returns only copy button when only copy is selected in toolbarOptions and copy is enabled', (WidgetTester tester) async {
2274+ const String text = 'TEXT';
2275+ final TextEditingController controller = TextEditingController(text: text);
2276+
2277+ await tester.pumpWidget(
2278+ MaterialApp(
2279+ home: EditableText(
2280+ controller: controller,
2281+ toolbarOptions: const ToolbarOptions(copy: true),
2282+ focusNode: focusNode,
2283+ style: textStyle,
2284+ cursorColor: cursorColor,
2285+ backgroundCursorColor: Colors.grey,
2286+ ),
2287+ ),
2288+ );
2289+
2290+ final EditableTextState state = tester.state<EditableTextState>(
2291+ find.byType(EditableText),
2292+ );
2293+
2294+ // Selecting all.
2295+ controller.selection = TextSelection(
2296+ baseOffset: 0,
2297+ extentOffset: controller.text.length,
2298+ );
2299+ expect(state.copyEnabled, isTrue);
2300+
2301+ final List<ContextMenuButtonItem>? items = state.buttonItemsForToolbarOptions();
2302+
2303+ expect(items, isNotNull);
2304+ expect(items, hasLength(1));
2305+
2306+ final ContextMenuButtonItem copyButton = items!.first;
2307+ expect(copyButton.type, ContextMenuButtonType.copy);
2308+
2309+ copyButton.onPressed();
2310+ await tester.pump();
2311+
2312+ expect(controller.text, equals(text));
2313+ final ClipboardData? data = await Clipboard.getData('text/plain');
2314+ expect(data, isNotNull);
2315+ expect(data!.text, equals(text));
2316+ });
2317+
2318+ testWidgets('returns empty array when only paste is selected in toolbarOptions but paste is not enabled', (WidgetTester tester) async {
2319+ await tester.pumpWidget(
2320+ MaterialApp(
2321+ home: EditableText(
2322+ controller: TextEditingController(text: 'TEXT'),
2323+ toolbarOptions: const ToolbarOptions(paste: true),
2324+ readOnly: true,
2325+ focusNode: focusNode,
2326+ style: textStyle,
2327+ cursorColor: cursorColor,
2328+ backgroundCursorColor: Colors.grey,
2329+ ),
2330+ ),
2331+ );
2332+
2333+ final EditableTextState state = tester.state<EditableTextState>(
2334+ find.byType(EditableText),
2335+ );
2336+
2337+ expect(state.pasteEnabled, isFalse);
2338+ expect(state.buttonItemsForToolbarOptions(), isEmpty);
2339+ });
2340+
2341+ testWidgets('returns only paste button when only paste is selected in toolbarOptions and paste is enabled', (WidgetTester tester) async {
2342+ const String text = 'TEXT';
2343+ final TextEditingController controller = TextEditingController(text: text);
2344+
2345+ await tester.pumpWidget(
2346+ MaterialApp(
2347+ home: EditableText(
2348+ controller: controller,
2349+ toolbarOptions: const ToolbarOptions(paste: true),
2350+ focusNode: focusNode,
2351+ style: textStyle,
2352+ cursorColor: cursorColor,
2353+ backgroundCursorColor: Colors.grey,
2354+ ),
2355+ ),
2356+ );
2357+
2358+ final EditableTextState state = tester.state<EditableTextState>(
2359+ find.byType(EditableText),
2360+ );
2361+
2362+ // Moving caret to the end.
2363+ controller.selection = TextSelection.collapsed(offset: controller.text.length);
2364+ expect(state.pasteEnabled, isTrue);
2365+
2366+ final List<ContextMenuButtonItem>? items = state.buttonItemsForToolbarOptions();
2367+
2368+ expect(items, isNotNull);
2369+ expect(items, hasLength(1));
2370+
2371+ final ContextMenuButtonItem pasteButton = items!.first;
2372+ expect(pasteButton.type, ContextMenuButtonType.paste);
2373+
2374+ // Setting data which will be pasted into the clipboard.
2375+ await Clipboard.setData(const ClipboardData(text: text));
2376+
2377+ pasteButton.onPressed();
2378+ await tester.pump();
2379+
2380+ expect(controller.text, equals(text + text));
2381+ });
2382+
2383+ testWidgets('returns empty array when only selectAll is selected in toolbarOptions but selectAll is not enabled', (WidgetTester tester) async {
2384+ await tester.pumpWidget(
2385+ MaterialApp(
2386+ home: EditableText(
2387+ controller: TextEditingController(text: 'TEXT'),
2388+ toolbarOptions: const ToolbarOptions(selectAll: true),
2389+ readOnly: true,
2390+ obscureText: true,
2391+ focusNode: focusNode,
2392+ style: textStyle,
2393+ cursorColor: cursorColor,
2394+ backgroundCursorColor: Colors.grey,
2395+ ),
2396+ ),
2397+ );
2398+
2399+ final EditableTextState state = tester.state<EditableTextState>(
2400+ find.byType(EditableText),
2401+ );
2402+
2403+ expect(state.selectAllEnabled, isFalse);
2404+ expect(state.buttonItemsForToolbarOptions(), isEmpty);
2405+ });
2406+
2407+ testWidgets('returns only selectAll button when only selectAll is selected in toolbarOptions and selectAll is enabled', (WidgetTester tester) async {
2408+ const String text = 'TEXT';
2409+ final TextEditingController controller = TextEditingController(text: text);
2410+
2411+ await tester.pumpWidget(
2412+ MaterialApp(
2413+ home: EditableText(
2414+ controller: controller,
2415+ toolbarOptions: const ToolbarOptions(selectAll: true),
2416+ focusNode: focusNode,
2417+ style: textStyle,
2418+ cursorColor: cursorColor,
2419+ backgroundCursorColor: Colors.grey,
2420+ ),
2421+ ),
2422+ );
2423+
2424+ final EditableTextState state = tester.state<EditableTextState>(
2425+ find.byType(EditableText),
2426+ );
2427+
2428+ final List<ContextMenuButtonItem>? items = state.buttonItemsForToolbarOptions();
2429+
2430+ expect(items, isNotNull);
2431+ expect(items, hasLength(1));
2432+
2433+ final ContextMenuButtonItem selectAllButton = items!.first;
2434+ expect(selectAllButton.type, ContextMenuButtonType.selectAll);
2435+
2436+ selectAllButton.onPressed();
2437+ await tester.pump();
2438+
2439+ expect(controller.text, equals(text));
2440+ expect(state.textEditingValue.selection.textInside(text), equals(text));
2441+ });
2442+ });
2443+
21602444 testWidgets('Handles the read-only flag correctly', (WidgetTester tester) async {
21612445 final TextEditingController controller =
21622446 TextEditingController(text: 'Lorem ipsum dolor sit amet');
0 commit comments