| Flutter macOS Embedder |

FlutterMenuPluginTest.mm
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #import "flutter/shell/platform/darwin/macos/framework/Headers/FlutterPluginMacOS.h"
6 #import "flutter/shell/platform/darwin/macos/framework/Headers/FlutterPluginRegistrarMacOS.h"
7 #import "flutter/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h"
8 #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterDartProject_Internal.h"
9 #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h"
10 #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterMenuPlugin.h"
11 #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterMenuPlugin_Internal.h"
12 #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterTextInputSemanticsObject.h"
13 #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterViewController_Internal.h"
14
15 #include "flutter/shell/platform/common/platform_provided_menu.h"
16 #include "gtest/gtest.h"
17
18 #import <OCMock/OCMock.h>
19 #import "flutter/testing/testing.h"
20
21 @interface FlutterMenuPluginTestObjc : NSObject
22 - (bool)testSetMenu;
23 @end
24
25 @implementation FlutterMenuPluginTestObjc
26
27 - (bool)testSetMenu {
28 // Workaround to deflake the test.
29 // See: https://github.com/flutter/flutter/issues/104748#issuecomment-1159336728
30 NSView* view = [[NSView alloc] initWithFrame:NSZeroRect];
31 view.wantsLayer = YES;
32
33 // Build a simulation of the default main menu.
34 NSMenu* mainMenu = [[NSMenu alloc] init];
35 NSMenuItem* appNameMenu = [[NSMenuItem alloc] initWithTitle:@"APP_NAME"
36 action:nil
37 keyEquivalent:@""];
38 NSMenu* submenu = [[NSMenu alloc] initWithTitle:@"Prexisting APP_NAME menu"];
39 [submenu addItem:[[NSMenuItem alloc] initWithTitle:@"About APP_NAME"
40 action:nil
41 keyEquivalent:@""]];
42 appNameMenu.submenu = submenu;
43 [mainMenu addItem:appNameMenu];
44 [NSApp setMainMenu:mainMenu];
45
46 id<FlutterPluginRegistrar> pluginRegistrarMock =
47 OCMProtocolMock(@protocol(FlutterPluginRegistrar));
48 __block FlutterMethodChannel* pluginChannel;
49 __block FlutterMenuPlugin* plugin;
50 id binaryMessengerMock = OCMProtocolMock(@protocol(FlutterBinaryMessenger));
51 OCMStub([pluginRegistrarMock messenger]).andReturn(binaryMessengerMock);
52 OCMStub( // NOLINT(google-objc-avoid-throwing-exception)
53 [pluginRegistrarMock addMethodCallDelegate:[OCMArg any] channel:[OCMArg any]])
54 .andDo(^(NSInvocation* invocation) {
55 id<FlutterPlugin> delegate;
56 FlutterMethodChannel* channel;
57 [invocation getArgument:&delegate atIndex:2];
58 [invocation getArgument:&channel atIndex:3];
59 pluginChannel = channel;
60 plugin = delegate;
61 [channel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
62 [delegate handleMethodCall:call result:result];
63 }];
64 });
65 [FlutterMenuPlugin registerWithRegistrar:pluginRegistrarMock];
66
67 NSDictionary* testMenus = @{
68 @"0" : @[
69 @{
70 @"id" : [NSNumber numberWithInt:1],
71 @"label" : @"APP_NAME",
72 @"enabled" : @(YES),
73 @"children" : @[
74 @{
75 @"id" : [NSNumber numberWithInt:3],
76 @"platformProvidedMenu" : @(static_cast<int>(flutter::PlatformProvidedMenu::kQuit)),
77 @"enabled" : @(YES),
78 },
79 @{
80 @"id" : [NSNumber numberWithInt:2],
81 @"label" : @"APP_NAME Info",
82 @"enabled" : @(YES),
83 @"shortcutTrigger" : [NSNumber numberWithUnsignedLongLong:0x61],
84 @"shortcutModifiers" : [NSNumber numberWithUnsignedInt:0],
85 },
86 ],
87 },
88 @{
89 @"id" : [NSNumber numberWithInt:4],
90 @"label" : @"Help for APP_NAME",
91 @"enabled" : @(YES),
92 @"children" : @[
93 @{
94 @"id" : [NSNumber numberWithInt:5],
95 @"label" : @"Help me!",
96 @"enabled" : @(YES),
97 },
98 @{
99 @"id" : [NSNumber numberWithInt:6],
100 @"label" : @"",
101 @"enabled" : @(NO),
102 @"isDivider" : @(YES),
103 },
104 @{
105 @"id" : [NSNumber numberWithInt:7],
106 @"label" : @"Search help",
107 @"enabled" : @(NO),
108 },
109 ],
110 },
111 ],
112 };
113
114 __block id available = @NO;
115 [plugin handleMethodCall:[FlutterMethodCall methodCallWithMethodName:@"Menu.isPluginAvailable"
116 arguments:nil]
117 result:^(id _Nullable result) {
118 available = result;
119 }];
120
121 EXPECT_TRUE(available);
122
123 [plugin handleMethodCall:[FlutterMethodCall methodCallWithMethodName:@"Menu.setMenus"
124 arguments:testMenus]
125 result:^(id _Nullable result){
126 }];
127
128 EXPECT_EQ([NSApp.mainMenu numberOfItems], 2);
129 NSMenuItem* firstMenu = [NSApp.mainMenu itemAtIndex:0];
130 EXPECT_TRUE([[firstMenu title] isEqualToString:@"flutter_desktop_darwin_unittests"]);
131 EXPECT_EQ([firstMenu tag], 1);
132 EXPECT_TRUE([firstMenu isEnabled]);
133 EXPECT_FALSE([firstMenu isHidden]);
134 EXPECT_TRUE([[firstMenu keyEquivalent] isEqualToString:@"\0"]);
135
136 EXPECT_EQ([[firstMenu submenu] numberOfItems], 1);
137 NSMenuItem* firstItem = [[firstMenu submenu] itemAtIndex:0];
138 EXPECT_TRUE([[firstItem title] isEqualToString:@"flutter_desktop_darwin_unittests Info"]);
139 EXPECT_TRUE([[firstItem keyEquivalent] isEqualToString:@"a"]);
140 EXPECT_TRUE([firstItem isEnabled]);
141 EXPECT_FALSE([firstItem isHidden]);
142 EXPECT_TRUE(
143 [NSStringFromSelector([firstItem action]) isEqualToString:@"flutterMenuItemSelected:"]);
144 EXPECT_EQ([firstItem tag], 2);
145
146 NSMenuItem* secondMenu = [NSApp.mainMenu itemAtIndex:1];
147 EXPECT_TRUE([[secondMenu title] isEqualToString:@"Help for flutter_desktop_darwin_unittests"]);
148 EXPECT_EQ([secondMenu tag], 4);
149 EXPECT_TRUE([secondMenu isEnabled]);
150 EXPECT_FALSE([secondMenu isHidden]);
151
152 EXPECT_EQ([[secondMenu submenu] numberOfItems], 3);
153 NSMenuItem* secondMenuFirst = [[secondMenu submenu] itemAtIndex:0];
154 EXPECT_TRUE([[secondMenuFirst title] isEqualToString:@"Help me!"]);
155 EXPECT_TRUE([secondMenuFirst isEnabled]);
156 EXPECT_FALSE([secondMenuFirst isHidden]);
157 EXPECT_TRUE(
158 [NSStringFromSelector([secondMenuFirst action]) isEqualToString:@"flutterMenuItemSelected:"]);
159 EXPECT_EQ([secondMenuFirst tag], 5);
160
161 NSMenuItem* secondMenuDivider = [[secondMenu submenu] itemAtIndex:1];
162 EXPECT_TRUE([[secondMenuDivider title] isEqualToString:@""]);
163 EXPECT_TRUE([[secondMenuDivider keyEquivalent] isEqualToString:@""]);
164 EXPECT_FALSE([secondMenuDivider isEnabled]);
165 EXPECT_FALSE([secondMenuDivider isHidden]);
166 EXPECT_EQ([secondMenuDivider action], nil);
167 EXPECT_EQ([secondMenuDivider tag], 0);
168
169 NSMenuItem* secondMenuLast = [[secondMenu submenu] itemAtIndex:2];
170 EXPECT_TRUE([[secondMenuLast title] isEqualToString:@"Search help"]);
171 EXPECT_FALSE([secondMenuLast isEnabled]);
172 EXPECT_FALSE([secondMenuLast isHidden]);
173 EXPECT_TRUE(
174 [NSStringFromSelector([secondMenuLast action]) isEqualToString:@"flutterMenuItemSelected:"]);
175 EXPECT_EQ([secondMenuLast tag], 7);
176
177 return true;
178 }
179
180 @end
181
182 namespace flutter::testing {
183 TEST(FlutterMenuPluginTest, TestSetMenu) {
184 ASSERT_TRUE([[FlutterMenuPluginTestObjc alloc] testSetMenu]);
185 }
186 } // namespace flutter::testing
+[FlutterMethodCall methodCallWithMethodName:arguments:]
instancetype methodCallWithMethodName:arguments:(NSString *method,[arguments] id _Nullable arguments)
FlutterMethodChannel
Definition: FlutterChannels.h:222
FlutterPluginMacOS.h
FlutterEngine_Internal.h
flutter::testing
Definition: AccessibilityBridgeMacTest.mm:11
FlutterPluginRegistrar-p
Definition: FlutterPluginRegistrarMacOS.h:25
FlutterPluginRegistrarMacOS.h
-[FlutterMethodChannel setMethodCallHandler:]
void setMethodCallHandler:(FlutterMethodCallHandler _Nullable handler)
FlutterMethodCall
Definition: FlutterCodecs.h:220
flutter::testing::TEST
TEST(AccessibilityBridgeMacTest, SendsAccessibilityCreateNotificationToWindowOfFlutterView)
Definition: AccessibilityBridgeMacTest.mm:61
FlutterDartProject_Internal.h
FlutterViewController_Internal.h
FlutterTextInputSemanticsObject.h
FlutterBinaryMessenger-p
Definition: FlutterBinaryMessenger.h:48
FlutterViewController.h