api_event_handler_unittest.cc 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266
  1. // Copyright 2016 The Chromium 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. #include "extensions/renderer/bindings/api_event_handler.h"
  5. #include "base/bind.h"
  6. #include "base/callback_helpers.h"
  7. #include "base/run_loop.h"
  8. #include "base/test/bind.h"
  9. #include "base/test/mock_callback.h"
  10. #include "base/values.h"
  11. #include "extensions/common/mojom/event_dispatcher.mojom.h"
  12. #include "extensions/renderer/bindings/api_binding_test.h"
  13. #include "extensions/renderer/bindings/api_binding_test_util.h"
  14. #include "extensions/renderer/bindings/exception_handler.h"
  15. #include "extensions/renderer/bindings/test_js_runner.h"
  16. #include "gin/arguments.h"
  17. #include "gin/converter.h"
  18. #include "gin/public/context_holder.h"
  19. #include "testing/gmock/include/gmock/gmock.h"
  20. #include "third_party/abseil-cpp/absl/types/optional.h"
  21. namespace extensions {
  22. namespace {
  23. using MockEventChangeHandler = ::testing::StrictMock<
  24. base::MockCallback<APIEventListeners::ListenersUpdated>>;
  25. std::string GetContextOwner(v8::Local<v8::Context> context) {
  26. return "context";
  27. }
  28. // Note: Not function-local to RemoveListener() because it's used in one place
  29. // that needs to circumvent RunFunction().
  30. constexpr char kRemoveListenerFunction[] =
  31. "(function(event, listener) { event.removeListener(listener); })";
  32. void AddListener(v8::Local<v8::Context> context,
  33. v8::Local<v8::Function> listener,
  34. v8::Local<v8::Object> event) {
  35. constexpr char kAddListenerFunction[] =
  36. "(function(event, listener) { event.addListener(listener); })";
  37. v8::Local<v8::Function> add_listener =
  38. FunctionFromString(context, kAddListenerFunction);
  39. v8::Local<v8::Value> argv[] = {event, listener};
  40. RunFunction(add_listener, context, std::size(argv), argv);
  41. }
  42. void RemoveListener(v8::Local<v8::Context> context,
  43. v8::Local<v8::Function> listener,
  44. v8::Local<v8::Object> event) {
  45. v8::Local<v8::Function> remove_listener =
  46. FunctionFromString(context, kRemoveListenerFunction);
  47. v8::Local<v8::Value> argv[] = {event, listener};
  48. RunFunction(remove_listener, context, std::size(argv), argv);
  49. }
  50. class APIEventHandlerTest : public APIBindingTest {
  51. public:
  52. APIEventHandlerTest(const APIEventHandlerTest&) = delete;
  53. APIEventHandlerTest& operator=(const APIEventHandlerTest&) = delete;
  54. protected:
  55. APIEventHandlerTest() {}
  56. ~APIEventHandlerTest() override {}
  57. void SetUp() override {
  58. APIBindingTest::SetUp();
  59. handler_ = std::make_unique<APIEventHandler>(
  60. base::DoNothing(), base::BindRepeating(&GetContextOwner), nullptr);
  61. }
  62. void TearDown() override {
  63. DisposeAllContexts();
  64. handler_.reset();
  65. APIBindingTest::TearDown();
  66. }
  67. void OnWillDisposeContext(v8::Local<v8::Context> context) override {
  68. ASSERT_TRUE(handler_);
  69. handler_->InvalidateContext(context);
  70. }
  71. void SetHandler(std::unique_ptr<APIEventHandler> handler) {
  72. handler_ = std::move(handler);
  73. }
  74. APIEventHandler* handler() { return handler_.get(); }
  75. private:
  76. std::unique_ptr<APIEventHandler> handler_;
  77. };
  78. } // namespace
  79. // Tests adding, removing, and querying event listeners by calling the
  80. // associated methods on the JS object.
  81. TEST_F(APIEventHandlerTest, AddingRemovingAndQueryingEventListeners) {
  82. const char kEventName[] = "alpha";
  83. v8::HandleScope handle_scope(isolate());
  84. v8::Local<v8::Context> context = MainContext();
  85. v8::Local<v8::Object> event = handler()->CreateEventInstance(
  86. kEventName, false, true, binding::kNoListenerMax, true, context);
  87. ASSERT_FALSE(event.IsEmpty());
  88. EXPECT_EQ(0u, handler()->GetNumEventListenersForTesting(kEventName, context));
  89. const char kListenerFunction[] = "(function() {})";
  90. v8::Local<v8::Function> listener_function =
  91. FunctionFromString(context, kListenerFunction);
  92. ASSERT_FALSE(listener_function.IsEmpty());
  93. AddListener(context, listener_function, event);
  94. // There should only be one listener on the event.
  95. EXPECT_EQ(1u, handler()->GetNumEventListenersForTesting(kEventName, context));
  96. AddListener(context, listener_function, event);
  97. // Trying to add the same listener again should be a no-op.
  98. EXPECT_EQ(1u, handler()->GetNumEventListenersForTesting(kEventName, context));
  99. // Test hasListener returns true for a listener that is present.
  100. const char kHasListenerFunction[] =
  101. "(function(event, listener) { return event.hasListener(listener); })";
  102. v8::Local<v8::Function> has_listener_function =
  103. FunctionFromString(context, kHasListenerFunction);
  104. {
  105. v8::Local<v8::Value> argv[] = {event, listener_function};
  106. v8::Local<v8::Value> result =
  107. RunFunction(has_listener_function, context, std::size(argv), argv);
  108. bool has_listener = false;
  109. EXPECT_TRUE(gin::Converter<bool>::FromV8(isolate(), result, &has_listener));
  110. EXPECT_TRUE(has_listener);
  111. }
  112. // Test that hasListener returns false for a listener that isn't present.
  113. {
  114. v8::Local<v8::Function> not_a_listener =
  115. FunctionFromString(context, "(function() {})");
  116. v8::Local<v8::Value> argv[] = {event, not_a_listener};
  117. v8::Local<v8::Value> result =
  118. RunFunction(has_listener_function, context, std::size(argv), argv);
  119. bool has_listener = false;
  120. EXPECT_TRUE(gin::Converter<bool>::FromV8(isolate(), result, &has_listener));
  121. EXPECT_FALSE(has_listener);
  122. }
  123. // Test hasListeners returns true
  124. const char kHasListenersFunction[] =
  125. "(function(event) { return event.hasListeners(); })";
  126. v8::Local<v8::Function> has_listeners_function =
  127. FunctionFromString(context, kHasListenersFunction);
  128. {
  129. v8::Local<v8::Value> argv[] = {event};
  130. v8::Local<v8::Value> result =
  131. RunFunction(has_listeners_function, context, std::size(argv), argv);
  132. bool has_listeners = false;
  133. EXPECT_TRUE(
  134. gin::Converter<bool>::FromV8(isolate(), result, &has_listeners));
  135. EXPECT_TRUE(has_listeners);
  136. }
  137. RemoveListener(context, listener_function, event);
  138. EXPECT_EQ(0u, handler()->GetNumEventListenersForTesting(kEventName, context));
  139. {
  140. v8::Local<v8::Value> argv[] = {event};
  141. v8::Local<v8::Value> result =
  142. RunFunction(has_listeners_function, context, std::size(argv), argv);
  143. bool has_listeners = false;
  144. EXPECT_TRUE(
  145. gin::Converter<bool>::FromV8(isolate(), result, &has_listeners));
  146. EXPECT_FALSE(has_listeners);
  147. }
  148. }
  149. // Tests listening for and firing different events.
  150. TEST_F(APIEventHandlerTest, FiringEvents) {
  151. const char kAlphaName[] = "alpha";
  152. const char kBetaName[] = "beta";
  153. v8::HandleScope handle_scope(isolate());
  154. v8::Local<v8::Context> context = MainContext();
  155. v8::Local<v8::Object> alpha_event = handler()->CreateEventInstance(
  156. kAlphaName, false, true, binding::kNoListenerMax, true, context);
  157. v8::Local<v8::Object> beta_event = handler()->CreateEventInstance(
  158. kBetaName, false, true, binding::kNoListenerMax, true, context);
  159. ASSERT_FALSE(alpha_event.IsEmpty());
  160. ASSERT_FALSE(beta_event.IsEmpty());
  161. const char kAlphaListenerFunction1[] =
  162. "(function() {\n"
  163. " if (!this.alphaCount1) this.alphaCount1 = 0;\n"
  164. " ++this.alphaCount1;\n"
  165. "});\n";
  166. v8::Local<v8::Function> alpha_listener1 =
  167. FunctionFromString(context, kAlphaListenerFunction1);
  168. const char kAlphaListenerFunction2[] =
  169. "(function() {\n"
  170. " if (!this.alphaCount2) this.alphaCount2 = 0;\n"
  171. " ++this.alphaCount2;\n"
  172. "});\n";
  173. v8::Local<v8::Function> alpha_listener2 =
  174. FunctionFromString(context, kAlphaListenerFunction2);
  175. const char kBetaListenerFunction[] =
  176. "(function() {\n"
  177. " if (!this.betaCount) this.betaCount = 0;\n"
  178. " ++this.betaCount;\n"
  179. "});\n";
  180. v8::Local<v8::Function> beta_listener =
  181. FunctionFromString(context, kBetaListenerFunction);
  182. ASSERT_FALSE(alpha_listener1.IsEmpty());
  183. ASSERT_FALSE(alpha_listener2.IsEmpty());
  184. ASSERT_FALSE(beta_listener.IsEmpty());
  185. AddListener(context, alpha_listener1, alpha_event);
  186. AddListener(context, alpha_listener2, alpha_event);
  187. AddListener(context, beta_listener, beta_event);
  188. EXPECT_EQ(2u, handler()->GetNumEventListenersForTesting(kAlphaName, context));
  189. EXPECT_EQ(1u, handler()->GetNumEventListenersForTesting(kBetaName, context));
  190. auto get_fired_count = [&context](const char* name) {
  191. v8::Local<v8::Value> res =
  192. GetPropertyFromObject(context->Global(), context, name);
  193. if (res->IsUndefined())
  194. return 0;
  195. int32_t count = 0;
  196. EXPECT_TRUE(
  197. gin::Converter<int32_t>::FromV8(context->GetIsolate(), res, &count))
  198. << name;
  199. return count;
  200. };
  201. EXPECT_EQ(0, get_fired_count("alphaCount1"));
  202. EXPECT_EQ(0, get_fired_count("alphaCount2"));
  203. EXPECT_EQ(0, get_fired_count("betaCount"));
  204. handler()->FireEventInContext(kAlphaName, context, base::Value::List(),
  205. nullptr);
  206. EXPECT_EQ(2u, handler()->GetNumEventListenersForTesting(kAlphaName, context));
  207. EXPECT_EQ(1u, handler()->GetNumEventListenersForTesting(kBetaName, context));
  208. EXPECT_EQ(1, get_fired_count("alphaCount1"));
  209. EXPECT_EQ(1, get_fired_count("alphaCount2"));
  210. EXPECT_EQ(0, get_fired_count("betaCount"));
  211. handler()->FireEventInContext(kAlphaName, context, base::Value::List(),
  212. nullptr);
  213. EXPECT_EQ(2, get_fired_count("alphaCount1"));
  214. EXPECT_EQ(2, get_fired_count("alphaCount2"));
  215. EXPECT_EQ(0, get_fired_count("betaCount"));
  216. handler()->FireEventInContext(kBetaName, context, base::Value::List(),
  217. nullptr);
  218. EXPECT_EQ(2, get_fired_count("alphaCount1"));
  219. EXPECT_EQ(2, get_fired_count("alphaCount2"));
  220. EXPECT_EQ(1, get_fired_count("betaCount"));
  221. }
  222. // Tests firing events with arguments.
  223. TEST_F(APIEventHandlerTest, EventArguments) {
  224. v8::HandleScope handle_scope(isolate());
  225. v8::Local<v8::Context> context = MainContext();
  226. const char kEventName[] = "alpha";
  227. v8::Local<v8::Object> event = handler()->CreateEventInstance(
  228. kEventName, false, true, binding::kNoListenerMax, true, context);
  229. ASSERT_FALSE(event.IsEmpty());
  230. const char kListenerFunction[] =
  231. "(function() { this.eventArgs = Array.from(arguments); })";
  232. v8::Local<v8::Function> listener_function =
  233. FunctionFromString(context, kListenerFunction);
  234. ASSERT_FALSE(listener_function.IsEmpty());
  235. AddListener(context, listener_function, event);
  236. const char kArguments[] = "['foo',1,{'prop1':'bar'}]";
  237. base::Value::List event_args = ListValueFromString(kArguments);
  238. handler()->FireEventInContext(kEventName, context, event_args, nullptr);
  239. EXPECT_EQ(
  240. ReplaceSingleQuotes(kArguments),
  241. GetStringPropertyFromObject(context->Global(), context, "eventArgs"));
  242. }
  243. // Test dispatching events to multiple contexts.
  244. TEST_F(APIEventHandlerTest, MultipleContexts) {
  245. v8::HandleScope handle_scope(isolate());
  246. v8::Local<v8::Context> context_a = MainContext();
  247. v8::Local<v8::Context> context_b = AddContext();
  248. const char kEventName[] = "onFoo";
  249. v8::Local<v8::Function> listener_a = FunctionFromString(
  250. context_a, "(function(arg) { this.eventArgs = arg + 'alpha'; })");
  251. ASSERT_FALSE(listener_a.IsEmpty());
  252. v8::Local<v8::Function> listener_b = FunctionFromString(
  253. context_b, "(function(arg) { this.eventArgs = arg + 'beta'; })");
  254. ASSERT_FALSE(listener_b.IsEmpty());
  255. // Create two instances of the same event in different contexts.
  256. v8::Local<v8::Object> event_a = handler()->CreateEventInstance(
  257. kEventName, false, true, binding::kNoListenerMax, true, context_a);
  258. ASSERT_FALSE(event_a.IsEmpty());
  259. v8::Local<v8::Object> event_b = handler()->CreateEventInstance(
  260. kEventName, false, true, binding::kNoListenerMax, true, context_b);
  261. ASSERT_FALSE(event_b.IsEmpty());
  262. // Add two separate listeners to the event, one in each context.
  263. AddListener(context_a, listener_a, event_a);
  264. EXPECT_EQ(1u,
  265. handler()->GetNumEventListenersForTesting(kEventName, context_a));
  266. EXPECT_EQ(0u,
  267. handler()->GetNumEventListenersForTesting(kEventName, context_b));
  268. AddListener(context_b, listener_b, event_b);
  269. EXPECT_EQ(1u,
  270. handler()->GetNumEventListenersForTesting(kEventName, context_a));
  271. EXPECT_EQ(1u,
  272. handler()->GetNumEventListenersForTesting(kEventName, context_b));
  273. // Dispatch the event in context_a - the listener in context_b should not be
  274. // notified.
  275. base::Value::List arguments_a = ListValueFromString("['result_a:']");
  276. handler()->FireEventInContext(kEventName, context_a, arguments_a, nullptr);
  277. {
  278. EXPECT_EQ("\"result_a:alpha\"",
  279. GetStringPropertyFromObject(context_a->Global(), context_a,
  280. "eventArgs"));
  281. }
  282. {
  283. EXPECT_EQ("undefined", GetStringPropertyFromObject(context_b->Global(),
  284. context_b, "eventArgs"));
  285. }
  286. // Dispatch the event in context_b - the listener in context_a should not be
  287. // notified.
  288. base::Value::List arguments_b = ListValueFromString("['result_b:']");
  289. handler()->FireEventInContext(kEventName, context_b, arguments_b, nullptr);
  290. {
  291. EXPECT_EQ("\"result_a:alpha\"",
  292. GetStringPropertyFromObject(context_a->Global(), context_a,
  293. "eventArgs"));
  294. }
  295. {
  296. EXPECT_EQ("\"result_b:beta\"",
  297. GetStringPropertyFromObject(context_b->Global(), context_b,
  298. "eventArgs"));
  299. }
  300. }
  301. TEST_F(APIEventHandlerTest, DifferentCallingMethods) {
  302. v8::HandleScope handle_scope(isolate());
  303. v8::Local<v8::Context> context = MainContext();
  304. const char kEventName[] = "alpha";
  305. v8::Local<v8::Object> event = handler()->CreateEventInstance(
  306. kEventName, false, true, binding::kNoListenerMax, true, context);
  307. ASSERT_FALSE(event.IsEmpty());
  308. const char kAddListenerOnNull[] =
  309. "(function(event) {\n"
  310. " event.addListener.call(null, function() {});\n"
  311. "})";
  312. {
  313. v8::Local<v8::Value> args[] = {event};
  314. RunFunctionAndExpectError(
  315. FunctionFromString(context, kAddListenerOnNull), context, 1, args,
  316. "Uncaught TypeError: Illegal invocation: Function must be called on "
  317. "an object of type Event");
  318. }
  319. EXPECT_EQ(0u, handler()->GetNumEventListenersForTesting(kEventName, context));
  320. const char kAddListenerOnEvent[] =
  321. "(function(event) {\n"
  322. " event.addListener.call(event, function() {});\n"
  323. "})";
  324. {
  325. v8::Local<v8::Value> args[] = {event};
  326. RunFunction(FunctionFromString(context, kAddListenerOnEvent),
  327. context, 1, args);
  328. }
  329. EXPECT_EQ(1u, handler()->GetNumEventListenersForTesting(kEventName, context));
  330. // Call addListener with a function that captures the event, creating a cycle.
  331. // If we don't properly clean up, the context will leak.
  332. const char kAddListenerOnEventWithCapture[] =
  333. "(function(event) {\n"
  334. " event.addListener(function listener() {\n"
  335. " event.hasListener(listener);\n"
  336. " });\n"
  337. "})";
  338. {
  339. v8::Local<v8::Value> args[] = {event};
  340. RunFunction(FunctionFromString(context, kAddListenerOnEventWithCapture),
  341. context, 1, args);
  342. }
  343. EXPECT_EQ(2u, handler()->GetNumEventListenersForTesting(kEventName, context));
  344. }
  345. TEST_F(APIEventHandlerTest, TestDispatchFromJs) {
  346. v8::HandleScope handle_scope(isolate());
  347. v8::Local<v8::Context> context = MainContext();
  348. v8::Local<v8::Object> event = handler()->CreateEventInstance(
  349. "alpha", false, true, binding::kNoListenerMax, true, context);
  350. ASSERT_FALSE(event.IsEmpty());
  351. const char kListenerFunction[] =
  352. "(function() {\n"
  353. " this.eventArgs = Array.from(arguments);\n"
  354. "});";
  355. v8::Local<v8::Function> listener =
  356. FunctionFromString(context, kListenerFunction);
  357. AddListener(context, listener, event);
  358. v8::Local<v8::Function> fire_event_function =
  359. FunctionFromString(
  360. context,
  361. "(function(event) { event.dispatch(42, 'foo', {bar: 'baz'}); })");
  362. {
  363. v8::Local<v8::Value> argv[] = {event};
  364. RunFunctionOnGlobal(fire_event_function, context, std::size(argv), argv);
  365. }
  366. EXPECT_EQ("[42,\"foo\",{\"bar\":\"baz\"}]",
  367. GetStringPropertyFromObject(
  368. context->Global(), context, "eventArgs"));
  369. }
  370. // Test listeners that remove themselves in their handling of the event.
  371. TEST_F(APIEventHandlerTest, RemovingListenersWhileHandlingEvent) {
  372. v8::HandleScope handle_scope(isolate());
  373. v8::Local<v8::Context> context = MainContext();
  374. const char kEventName[] = "alpha";
  375. v8::Local<v8::Object> event = handler()->CreateEventInstance(
  376. kEventName, false, true, binding::kNoListenerMax, true, context);
  377. ASSERT_FALSE(event.IsEmpty());
  378. {
  379. // Cache the event object on the global in order to allow for easy removal.
  380. v8::Local<v8::Function> set_event_on_global =
  381. FunctionFromString(
  382. context,
  383. "(function(event) { this.testEvent = event; })");
  384. v8::Local<v8::Value> args[] = {event};
  385. RunFunctionOnGlobal(set_event_on_global, context, std::size(args), args);
  386. EXPECT_EQ(event,
  387. GetPropertyFromObject(context->Global(), context, "testEvent"));
  388. }
  389. // A listener function that removes itself as a listener.
  390. const char kListenerFunction[] =
  391. "(function() {\n"
  392. " return function listener() {\n"
  393. " this.testEvent.removeListener(listener);\n"
  394. " };\n"
  395. "})();";
  396. // Create and add a bunch of listeners.
  397. std::vector<v8::Local<v8::Function>> listeners;
  398. const size_t kNumListeners = 20u;
  399. listeners.reserve(kNumListeners);
  400. for (size_t i = 0; i < kNumListeners; ++i)
  401. listeners.push_back(FunctionFromString(context, kListenerFunction));
  402. for (const auto& listener : listeners)
  403. AddListener(context, listener, event);
  404. // Fire the event. All listeners should be removed (and we shouldn't crash).
  405. EXPECT_EQ(kNumListeners,
  406. handler()->GetNumEventListenersForTesting(kEventName, context));
  407. handler()->FireEventInContext(kEventName, context, base::Value::List(),
  408. nullptr);
  409. EXPECT_EQ(0u, handler()->GetNumEventListenersForTesting(kEventName, context));
  410. // TODO(devlin): Another possible test: register listener a and listener b,
  411. // where a removes b and b removes a. Theoretically, only one should be
  412. // notified. Investigate what we currently do in JS-style bindings.
  413. }
  414. // Test an event listener throwing an exception.
  415. TEST_F(APIEventHandlerTest, TestEventListenersThrowingExceptions) {
  416. auto log_error =
  417. [](std::vector<std::string>* errors_out, v8::Local<v8::Context> context,
  418. const std::string& error) { errors_out->push_back(error); };
  419. std::vector<std::string> logged_errors;
  420. ExceptionHandler exception_handler(
  421. base::BindRepeating(log_error, &logged_errors));
  422. SetHandler(std::make_unique<APIEventHandler>(
  423. base::DoNothing(), base::BindRepeating(&GetContextOwner),
  424. &exception_handler));
  425. v8::HandleScope handle_scope(isolate());
  426. v8::Local<v8::Context> context = MainContext();
  427. const char kEventName[] = "alpha";
  428. v8::Local<v8::Object> event = handler()->CreateEventInstance(
  429. kEventName, false, true, binding::kNoListenerMax, true, context);
  430. ASSERT_FALSE(event.IsEmpty());
  431. // A listener that will throw an exception. We guarantee that we throw the
  432. // exception first so that we don't rely on event listener ordering.
  433. const char kListenerFunction[] =
  434. "(function() {\n"
  435. " if (!this.didThrow) {\n"
  436. " this.didThrow = true;\n"
  437. " throw new Error('Event handler error');\n"
  438. " }\n"
  439. " this.eventArgs = Array.from(arguments);\n"
  440. "});";
  441. for (int i = 0; i < 2; ++i) {
  442. v8::Local<v8::Function> listener =
  443. FunctionFromString(context, kListenerFunction);
  444. AddListener(context, listener, event);
  445. }
  446. EXPECT_EQ(2u, handler()->GetNumEventListenersForTesting(kEventName, context));
  447. base::Value::List event_args = ListValueFromString("[42]");
  448. {
  449. TestJSRunner::AllowErrors allow_errors;
  450. handler()->FireEventInContext(kEventName, context, event_args, nullptr);
  451. }
  452. // An exception should have been thrown by the first listener and the second
  453. // listener should have recorded the event arguments.
  454. EXPECT_EQ("true", GetStringPropertyFromObject(context->Global(), context,
  455. "didThrow"));
  456. EXPECT_EQ("[42]", GetStringPropertyFromObject(context->Global(), context,
  457. "eventArgs"));
  458. ASSERT_EQ(1u, logged_errors.size());
  459. EXPECT_THAT(logged_errors[0],
  460. testing::StartsWith("Error in event handler: Error: "
  461. "Event handler error"));
  462. }
  463. // Tests being notified as listeners are added or removed from events.
  464. TEST_F(APIEventHandlerTest, CallbackNotifications) {
  465. MockEventChangeHandler change_handler;
  466. SetHandler(std::make_unique<APIEventHandler>(
  467. change_handler.Get(), base::BindRepeating(&GetContextOwner), nullptr));
  468. v8::HandleScope handle_scope(isolate());
  469. v8::Local<v8::Context> context_a = MainContext();
  470. v8::Local<v8::Context> context_b = AddContext();
  471. const char kEventName1[] = "onFoo";
  472. const char kEventName2[] = "onBar";
  473. v8::Local<v8::Object> event1_a = handler()->CreateEventInstance(
  474. kEventName1, false, true, binding::kNoListenerMax, true, context_a);
  475. ASSERT_FALSE(event1_a.IsEmpty());
  476. v8::Local<v8::Object> event2_a = handler()->CreateEventInstance(
  477. kEventName2, false, true, binding::kNoListenerMax, true, context_a);
  478. ASSERT_FALSE(event2_a.IsEmpty());
  479. v8::Local<v8::Object> event1_b = handler()->CreateEventInstance(
  480. kEventName1, false, true, binding::kNoListenerMax, true, context_b);
  481. ASSERT_FALSE(event1_b.IsEmpty());
  482. // Add a listener to the first event. The APIEventHandler should notify
  483. // since it's a change in state (no listeners -> listeners).
  484. v8::Local<v8::Function> listener1 =
  485. FunctionFromString(context_a, "(function() {})");
  486. {
  487. EXPECT_CALL(change_handler,
  488. Run(kEventName1,
  489. binding::EventListenersChanged::
  490. kFirstUnfilteredListenerForContextOwnerAdded,
  491. nullptr, true, context_a))
  492. .Times(1);
  493. AddListener(context_a, listener1, event1_a);
  494. ::testing::Mock::VerifyAndClearExpectations(&change_handler);
  495. }
  496. EXPECT_EQ(1u,
  497. handler()->GetNumEventListenersForTesting(kEventName1, context_a));
  498. // Add a second listener to the same event. We should not be notified, since
  499. // the event already had listeners.
  500. v8::Local<v8::Function> listener2 =
  501. FunctionFromString(context_a, "(function() {})");
  502. AddListener(context_a, listener2, event1_a);
  503. EXPECT_EQ(2u,
  504. handler()->GetNumEventListenersForTesting(kEventName1, context_a));
  505. // Remove the first listener of the event. Again, since the event has
  506. // listeners, we shouldn't be notified.
  507. RemoveListener(context_a, listener1, event1_a);
  508. EXPECT_EQ(1u,
  509. handler()->GetNumEventListenersForTesting(kEventName1, context_a));
  510. // Remove the final listener from the event. We should be notified that the
  511. // event no longer has listeners.
  512. {
  513. EXPECT_CALL(change_handler,
  514. Run(kEventName1,
  515. binding::EventListenersChanged::
  516. kLastUnfilteredListenerForContextOwnerRemoved,
  517. nullptr, true, context_a))
  518. .Times(1);
  519. RemoveListener(context_a, listener2, event1_a);
  520. ::testing::Mock::VerifyAndClearExpectations(&change_handler);
  521. }
  522. EXPECT_EQ(0u,
  523. handler()->GetNumEventListenersForTesting(kEventName1, context_a));
  524. // Add a listener to a separate event to ensure we receive the right
  525. // notifications.
  526. v8::Local<v8::Function> listener3 =
  527. FunctionFromString(context_a, "(function() {})");
  528. {
  529. EXPECT_CALL(change_handler,
  530. Run(kEventName2,
  531. binding::EventListenersChanged::
  532. kFirstUnfilteredListenerForContextOwnerAdded,
  533. nullptr, true, context_a))
  534. .Times(1);
  535. AddListener(context_a, listener3, event2_a);
  536. ::testing::Mock::VerifyAndClearExpectations(&change_handler);
  537. }
  538. EXPECT_EQ(1u,
  539. handler()->GetNumEventListenersForTesting(kEventName2, context_a));
  540. {
  541. EXPECT_CALL(change_handler,
  542. Run(kEventName1,
  543. binding::EventListenersChanged::
  544. kFirstUnfilteredListenerForContextOwnerAdded,
  545. nullptr, true, context_b))
  546. .Times(1);
  547. // And add a listener to an event in a different context to make sure the
  548. // associated context is correct.
  549. v8::Local<v8::Function> listener =
  550. FunctionFromString(context_b, "(function() {})");
  551. AddListener(context_b, listener, event1_b);
  552. ::testing::Mock::VerifyAndClearExpectations(&change_handler);
  553. }
  554. EXPECT_EQ(1u,
  555. handler()->GetNumEventListenersForTesting(kEventName1, context_b));
  556. // When the contexts are invalidated, we should receive listener removed
  557. // notifications. Additionally, since this was the context being torn down,
  558. // rather than a removeListener call, was_manual should be false.
  559. EXPECT_CALL(change_handler,
  560. Run(kEventName2,
  561. binding::EventListenersChanged::
  562. kLastUnfilteredListenerForContextOwnerRemoved,
  563. nullptr, false, context_a))
  564. .Times(1);
  565. DisposeContext(context_a);
  566. ::testing::Mock::VerifyAndClearExpectations(&change_handler);
  567. EXPECT_CALL(change_handler,
  568. Run(kEventName1,
  569. binding::EventListenersChanged::
  570. kLastUnfilteredListenerForContextOwnerRemoved,
  571. nullptr, false, context_b))
  572. .Times(1);
  573. DisposeContext(context_b);
  574. ::testing::Mock::VerifyAndClearExpectations(&change_handler);
  575. }
  576. // Test registering an argument massager for a given event.
  577. TEST_F(APIEventHandlerTest, TestArgumentMassagers) {
  578. v8::HandleScope handle_scope(isolate());
  579. v8::Local<v8::Context> context = MainContext();
  580. const char kEventName[] = "alpha";
  581. v8::Local<v8::Object> event = handler()->CreateEventInstance(
  582. kEventName, false, true, binding::kNoListenerMax, true, context);
  583. ASSERT_FALSE(event.IsEmpty());
  584. const char kArgumentMassager[] =
  585. "(function(originalArgs, dispatch) {\n"
  586. " this.originalArgs = originalArgs;\n"
  587. " dispatch(['primary', 'secondary']);\n"
  588. "});";
  589. v8::Local<v8::Function> massager =
  590. FunctionFromString(context, kArgumentMassager);
  591. handler()->RegisterArgumentMassager(context, "alpha", massager);
  592. const char kListenerFunction[] =
  593. "(function() { this.eventArgs = Array.from(arguments); })";
  594. v8::Local<v8::Function> listener_function =
  595. FunctionFromString(context, kListenerFunction);
  596. ASSERT_FALSE(listener_function.IsEmpty());
  597. AddListener(context, listener_function, event);
  598. const char kArguments[] = "['first','second']";
  599. base::Value::List event_args = ListValueFromString(kArguments);
  600. handler()->FireEventInContext(kEventName, context, event_args, nullptr);
  601. EXPECT_EQ(
  602. "[\"first\",\"second\"]",
  603. GetStringPropertyFromObject(context->Global(), context, "originalArgs"));
  604. EXPECT_EQ(
  605. "[\"primary\",\"secondary\"]",
  606. GetStringPropertyFromObject(context->Global(), context, "eventArgs"));
  607. }
  608. // Test registering an argument massager for a given event and dispatching
  609. // asynchronously.
  610. TEST_F(APIEventHandlerTest, TestArgumentMassagersAsyncDispatch) {
  611. v8::HandleScope handle_scope(isolate());
  612. v8::Local<v8::Context> context = MainContext();
  613. const char kEventName[] = "alpha";
  614. v8::Local<v8::Object> event = handler()->CreateEventInstance(
  615. kEventName, false, true, binding::kNoListenerMax, true, context);
  616. ASSERT_FALSE(event.IsEmpty());
  617. const char kArgumentMassager[] =
  618. "(function(originalArgs, dispatch) {\n"
  619. " this.originalArgs = originalArgs;\n"
  620. " this.dispatch = dispatch;\n"
  621. "});";
  622. v8::Local<v8::Function> massager =
  623. FunctionFromString(context, kArgumentMassager);
  624. handler()->RegisterArgumentMassager(context, "alpha", massager);
  625. const char kListenerFunction[] =
  626. "(function() { this.eventArgs = Array.from(arguments); })";
  627. v8::Local<v8::Function> listener_function =
  628. FunctionFromString(context, kListenerFunction);
  629. ASSERT_FALSE(listener_function.IsEmpty());
  630. AddListener(context, listener_function, event);
  631. const char kArguments[] = "['first','second']";
  632. base::Value::List event_args = ListValueFromString(kArguments);
  633. handler()->FireEventInContext(kEventName, context, event_args, nullptr);
  634. // The massager should have been triggered, but since it doesn't call
  635. // dispatch(), the listener shouldn't have been notified.
  636. EXPECT_EQ(
  637. "[\"first\",\"second\"]",
  638. GetStringPropertyFromObject(context->Global(), context, "originalArgs"));
  639. EXPECT_EQ("undefined", GetStringPropertyFromObject(context->Global(), context,
  640. "eventArgs"));
  641. // Dispatch the event.
  642. v8::Local<v8::Value> dispatch_value =
  643. GetPropertyFromObject(context->Global(), context, "dispatch");
  644. ASSERT_FALSE(dispatch_value.IsEmpty());
  645. ASSERT_TRUE(dispatch_value->IsFunction());
  646. v8::Local<v8::Value> dispatch_args[] = {
  647. V8ValueFromScriptSource(context, "['primary', 'secondary']"),
  648. };
  649. RunFunction(dispatch_value.As<v8::Function>(), context,
  650. std::size(dispatch_args), dispatch_args);
  651. EXPECT_EQ(
  652. "[\"primary\",\"secondary\"]",
  653. GetStringPropertyFromObject(context->Global(), context, "eventArgs"));
  654. }
  655. // Test registering an argument massager and never dispatching.
  656. TEST_F(APIEventHandlerTest, TestArgumentMassagersNeverDispatch) {
  657. v8::HandleScope handle_scope(isolate());
  658. v8::Local<v8::Context> context = MainContext();
  659. const char kEventName[] = "alpha";
  660. v8::Local<v8::Object> event = handler()->CreateEventInstance(
  661. kEventName, false, true, binding::kNoListenerMax, true, context);
  662. ASSERT_FALSE(event.IsEmpty());
  663. // A massager that never dispatches.
  664. const char kArgumentMassager[] = "(function(originalArgs, dispatch) {})";
  665. v8::Local<v8::Function> massager =
  666. FunctionFromString(context, kArgumentMassager);
  667. handler()->RegisterArgumentMassager(context, "alpha", massager);
  668. const char kListenerFunction[] = "(function() {})";
  669. v8::Local<v8::Function> listener_function =
  670. FunctionFromString(context, kListenerFunction);
  671. ASSERT_FALSE(listener_function.IsEmpty());
  672. AddListener(context, listener_function, event);
  673. handler()->FireEventInContext(kEventName, context, base::Value::List(),
  674. nullptr);
  675. // Nothing should blow up. (We tested in the previous test that the event
  676. // isn't notified without calling dispatch, so all there is to test here is
  677. // that we don't crash.)
  678. }
  679. // Test that event results of dispatch are passed to the calling argument
  680. // massager. Regression test for https://crbug.com/867310.
  681. TEST_F(APIEventHandlerTest, TestArgumentMassagersDispatchResult) {
  682. v8::HandleScope handle_scope(isolate());
  683. v8::Local<v8::Context> context = MainContext();
  684. const char kEventName[] = "alpha";
  685. v8::Local<v8::Object> event = handler()->CreateEventInstance(
  686. kEventName, false, true, binding::kNoListenerMax, true, context);
  687. ASSERT_FALSE(event.IsEmpty());
  688. const char kArgumentMassager[] =
  689. R"((function(originalArgs, dispatch) {
  690. this.dispatchResult = dispatch(['primary']);
  691. });)";
  692. v8::Local<v8::Function> massager =
  693. FunctionFromString(context, kArgumentMassager);
  694. handler()->RegisterArgumentMassager(context, kEventName, massager);
  695. const char kListenerFunction[] =
  696. R"((function(arg) {
  697. let res = arg == 'primary' ? 'listenerSuccess' : 'listenerFailure';
  698. this.listenerResult = res;
  699. return res;
  700. });)";
  701. v8::Local<v8::Function> listener_function =
  702. FunctionFromString(context, kListenerFunction);
  703. ASSERT_FALSE(listener_function.IsEmpty());
  704. AddListener(context, listener_function, event);
  705. handler()->FireEventInContext(kEventName, context, base::Value::List(),
  706. nullptr);
  707. EXPECT_EQ(
  708. R"({"results":["listenerSuccess"]})",
  709. GetStringPropertyFromObject(context->Global(), context,
  710. "dispatchResult"));
  711. EXPECT_EQ(
  712. R"("listenerSuccess")",
  713. GetStringPropertyFromObject(context->Global(), context,
  714. "listenerResult"));
  715. }
  716. // Test creating a custom event, as is done by a few of our custom bindings.
  717. TEST_F(APIEventHandlerTest, TestCreateCustomEvent) {
  718. v8::HandleScope handle_scope(isolate());
  719. v8::Local<v8::Context> context = MainContext();
  720. MockEventChangeHandler change_handler;
  721. APIEventHandler handler(change_handler.Get(),
  722. base::BindRepeating(&GetContextOwner), nullptr);
  723. v8::Local<v8::Object> event = handler.CreateAnonymousEventInstance(context);
  724. ASSERT_FALSE(event.IsEmpty());
  725. constexpr char kListenerFunction[] =
  726. R"((function() { this.eventArgs = Array.from(arguments); }))";
  727. v8::Local<v8::Function> listener =
  728. FunctionFromString(context, kListenerFunction);
  729. AddListener(context, listener, event);
  730. // Test dispatching to the listeners.
  731. const char kDispatchEventFunction[] =
  732. "(function(event) { event.dispatch(1, 2, 3); })";
  733. v8::Local<v8::Function> dispatch_function =
  734. FunctionFromString(context, kDispatchEventFunction);
  735. v8::Local<v8::Value> dispatch_argv[] = {event};
  736. RunFunction(dispatch_function, context, std::size(dispatch_argv),
  737. dispatch_argv);
  738. EXPECT_EQ("[1,2,3]", GetStringPropertyFromObject(context->Global(), context,
  739. "eventArgs"));
  740. // Clean up so we can re-check eventArgs.
  741. ASSERT_TRUE(context->Global()
  742. ->Delete(context, gin::StringToSymbol(isolate(), "eventArgs"))
  743. .FromJust());
  744. // Invalidate the event and try dispatching again. Nothing should happen.
  745. handler.InvalidateCustomEvent(context, event);
  746. RunFunction(dispatch_function, context, std::size(dispatch_argv),
  747. dispatch_argv);
  748. EXPECT_EQ("undefined", GetStringPropertyFromObject(context->Global(), context,
  749. "eventArgs"));
  750. }
  751. // Test adding a custom event with a cyclic dependency. Nothing should leak.
  752. TEST_F(APIEventHandlerTest, TestCreateCustomEventWithCyclicDependency) {
  753. v8::HandleScope handle_scope(isolate());
  754. v8::Local<v8::Context> context = MainContext();
  755. MockEventChangeHandler change_handler;
  756. APIEventHandler handler(change_handler.Get(),
  757. base::BindRepeating(&GetContextOwner), nullptr);
  758. v8::Local<v8::Object> event = handler.CreateAnonymousEventInstance(context);
  759. ASSERT_FALSE(event.IsEmpty());
  760. const char kLocalAddListenerFunction[] =
  761. "(function(event) {\n"
  762. " event.addListener(function() {}.bind(null, event));\n"
  763. "})";
  764. v8::Local<v8::Value> add_listener_argv[] = {event};
  765. RunFunction(FunctionFromString(context, kLocalAddListenerFunction), context,
  766. std::size(add_listener_argv), add_listener_argv);
  767. DisposeContext(context);
  768. }
  769. TEST_F(APIEventHandlerTest, TestUnmanagedEvents) {
  770. v8::HandleScope handle_scope(isolate());
  771. v8::Local<v8::Context> context = MainContext();
  772. auto fail_on_notified =
  773. [](const std::string& event_name, binding::EventListenersChanged changed,
  774. const base::DictionaryValue* filter, bool was_manual,
  775. v8::Local<v8::Context> context) { ADD_FAILURE(); };
  776. APIEventHandler handler(base::BindRepeating(fail_on_notified),
  777. base::BindRepeating(&GetContextOwner), nullptr);
  778. const char kEventName[] = "alpha";
  779. v8::Local<v8::Object> event = handler.CreateEventInstance(
  780. kEventName, false, true, binding::kNoListenerMax, false, context);
  781. const char kListener[] =
  782. R"((function() { this.eventArgs = Array.from(arguments); }))";
  783. v8::Local<v8::Function> listener = FunctionFromString(context, kListener);
  784. AddListener(context, listener, event);
  785. EXPECT_EQ(1u, handler.GetNumEventListenersForTesting(kEventName, context));
  786. handler.FireEventInContext(kEventName, context,
  787. ListValueFromString("[1, 'foo']"), nullptr);
  788. EXPECT_EQ("[1,\"foo\"]", GetStringPropertyFromObject(context->Global(),
  789. context, "eventArgs"));
  790. RemoveListener(context, listener, event);
  791. EXPECT_EQ(0u, handler.GetNumEventListenersForTesting(kEventName, context));
  792. }
  793. // Test callback notifications for events that don't support lazy listeners.
  794. TEST_F(APIEventHandlerTest, TestEventsWithoutLazyListeners) {
  795. MockEventChangeHandler change_handler;
  796. APIEventHandler handler(change_handler.Get(),
  797. base::BindRepeating(&GetContextOwner), nullptr);
  798. v8::HandleScope handle_scope(isolate());
  799. v8::Local<v8::Context> context = MainContext();
  800. const char kLazyListenersSupported[] = "supportsLazyListeners";
  801. const char kLazyListenersNotSupported[] = "noLazyListeners";
  802. v8::Local<v8::Object> lazy_listeners_supported =
  803. handler.CreateEventInstance(kLazyListenersSupported, false, true,
  804. binding::kNoListenerMax, true, context);
  805. v8::Local<v8::Object> lazy_listeners_not_supported =
  806. handler.CreateEventInstance(kLazyListenersNotSupported, false, false,
  807. binding::kNoListenerMax, true, context);
  808. ASSERT_FALSE(lazy_listeners_not_supported.IsEmpty());
  809. v8::Local<v8::Function> listener =
  810. FunctionFromString(context, "(function() {})");
  811. {
  812. EXPECT_CALL(change_handler,
  813. Run(kLazyListenersSupported,
  814. binding::EventListenersChanged::
  815. kFirstUnfilteredListenerForContextOwnerAdded,
  816. nullptr, true, context))
  817. .Times(1);
  818. AddListener(context, listener, lazy_listeners_supported);
  819. ::testing::Mock::VerifyAndClearExpectations(&change_handler);
  820. }
  821. {
  822. EXPECT_CALL(change_handler,
  823. Run(kLazyListenersNotSupported,
  824. binding::EventListenersChanged::
  825. kFirstUnfilteredListenerForContextOwnerAdded,
  826. nullptr, false, context))
  827. .Times(1);
  828. AddListener(context, listener, lazy_listeners_not_supported);
  829. ::testing::Mock::VerifyAndClearExpectations(&change_handler);
  830. }
  831. {
  832. EXPECT_CALL(change_handler,
  833. Run(kLazyListenersSupported,
  834. binding::EventListenersChanged::
  835. kLastUnfilteredListenerForContextOwnerRemoved,
  836. nullptr, true, context))
  837. .Times(1);
  838. RemoveListener(context, listener, lazy_listeners_supported);
  839. ::testing::Mock::VerifyAndClearExpectations(&change_handler);
  840. }
  841. {
  842. EXPECT_CALL(change_handler,
  843. Run(kLazyListenersNotSupported,
  844. binding::EventListenersChanged::
  845. kLastUnfilteredListenerForContextOwnerRemoved,
  846. nullptr, false, context))
  847. .Times(1);
  848. RemoveListener(context, listener, lazy_listeners_not_supported);
  849. ::testing::Mock::VerifyAndClearExpectations(&change_handler);
  850. }
  851. DisposeContext(context);
  852. }
  853. // Tests dispatching events while script is suspended.
  854. TEST_F(APIEventHandlerTest, TestDispatchingEventsWhileScriptSuspended) {
  855. const char kEventName[] = "alpha";
  856. v8::HandleScope handle_scope(isolate());
  857. v8::Local<v8::Context> context = MainContext();
  858. v8::Local<v8::Object> event = handler()->CreateEventInstance(
  859. kEventName, false, true, binding::kNoListenerMax, true, context);
  860. const char kListenerFunction[] = "(function() { this.eventFired = true; });";
  861. v8::Local<v8::Function> listener =
  862. FunctionFromString(context, kListenerFunction);
  863. AddListener(context, listener, event);
  864. {
  865. // Suspend script and fire an event. The listener should *not* be notified
  866. // while script is suspended.
  867. TestJSRunner::Suspension script_suspension;
  868. handler()->FireEventInContext(kEventName, context, base::Value::List(),
  869. nullptr);
  870. base::RunLoop().RunUntilIdle();
  871. EXPECT_EQ("undefined", GetStringPropertyFromObject(context->Global(),
  872. context, "eventFired"));
  873. }
  874. // After script resumes, the listener should be notified.
  875. EXPECT_EQ("true", GetStringPropertyFromObject(context->Global(), context,
  876. "eventFired"));
  877. }
  878. // Tests catching errors thrown by listeners while dispatching after script
  879. // suspension.
  880. TEST_F(APIEventHandlerTest,
  881. TestListenersThrowingExceptionsAfterScriptSuspension) {
  882. auto log_error =
  883. [](std::vector<std::string>* errors_out, v8::Local<v8::Context> context,
  884. const std::string& error) { errors_out->push_back(error); };
  885. std::vector<std::string> logged_errors;
  886. ExceptionHandler exception_handler(
  887. base::BindRepeating(log_error, &logged_errors));
  888. SetHandler(std::make_unique<APIEventHandler>(
  889. base::DoNothing(), base::BindRepeating(&GetContextOwner),
  890. &exception_handler));
  891. const char kEventName[] = "alpha";
  892. v8::HandleScope handle_scope(isolate());
  893. v8::Local<v8::Context> context = MainContext();
  894. v8::Local<v8::Object> event = handler()->CreateEventInstance(
  895. kEventName, false, true, binding::kNoListenerMax, true, context);
  896. const char kListenerFunction[] =
  897. "(function() {\n"
  898. " this.eventFired = true;\n"
  899. " throw new Error('hahaha');\n"
  900. "});";
  901. v8::Local<v8::Function> listener =
  902. FunctionFromString(context, kListenerFunction);
  903. AddListener(context, listener, event);
  904. TestJSRunner::AllowErrors allow_errors;
  905. {
  906. // Suspend script and fire an event. The listener should not be notified,
  907. // and no errors should be logged.
  908. TestJSRunner::Suspension script_suspension;
  909. handler()->FireEventInContext(kEventName, context, base::Value::List(),
  910. nullptr);
  911. base::RunLoop().RunUntilIdle();
  912. EXPECT_EQ("undefined", GetStringPropertyFromObject(context->Global(),
  913. context, "eventFired"));
  914. EXPECT_TRUE(logged_errors.empty());
  915. }
  916. // Once script resumes, the listener should have been notifed, and we should
  917. // have caught the error.
  918. EXPECT_EQ("true", GetStringPropertyFromObject(context->Global(), context,
  919. "eventFired"));
  920. ASSERT_EQ(1u, logged_errors.size());
  921. EXPECT_THAT(logged_errors[0],
  922. testing::StartsWith("Error in event handler: Error: hahaha"));
  923. }
  924. // Tests dispatching events when listeners are removed between when an event
  925. // was fired (during script suspension) and when the script runs.
  926. TEST_F(APIEventHandlerTest,
  927. TestDispatchingEventAfterListenersRemovedAfterScriptSuspension) {
  928. const char kEventName[] = "alpha";
  929. v8::HandleScope handle_scope(isolate());
  930. v8::Local<v8::Context> context = MainContext();
  931. v8::Local<v8::Object> event = handler()->CreateEventInstance(
  932. kEventName, false, true, binding::kNoListenerMax, true, context);
  933. const char kListenerFunction1[] =
  934. "(function() { this.eventFired1 = true; });";
  935. const char kListenerFunction2[] =
  936. "(function() { this.eventFired2 = true; });";
  937. v8::Local<v8::Function> listener1 =
  938. FunctionFromString(context, kListenerFunction1);
  939. v8::Local<v8::Function> listener2 =
  940. FunctionFromString(context, kListenerFunction2);
  941. // Add two event listeners.
  942. AddListener(context, listener1, event);
  943. AddListener(context, listener2, event);
  944. EXPECT_EQ(2u, handler()->GetNumEventListenersForTesting(kEventName, context));
  945. {
  946. // Suspend script, and then queue up a call to remove the first listener.
  947. TestJSRunner::Suspension script_suspension;
  948. v8::Local<v8::Function> remove_listener_function =
  949. FunctionFromString(context, kRemoveListenerFunction);
  950. {
  951. v8::Local<v8::Value> argv[] = {event, listener1};
  952. // Note: Use JSRunner() so that script suspension is respected.
  953. JSRunner::Get(context)->RunJSFunction(remove_listener_function, context,
  954. std::size(argv), argv);
  955. }
  956. // Since script has been suspended, there should still be two listeners, and
  957. // neither should have been notified.
  958. EXPECT_EQ(2u,
  959. handler()->GetNumEventListenersForTesting(kEventName, context));
  960. handler()->FireEventInContext(kEventName, context, base::Value::List(),
  961. nullptr);
  962. base::RunLoop().RunUntilIdle();
  963. EXPECT_EQ("undefined", GetStringPropertyFromObject(context->Global(),
  964. context, "eventFired1"));
  965. EXPECT_EQ("undefined", GetStringPropertyFromObject(context->Global(),
  966. context, "eventFired2"));
  967. }
  968. // Once script resumes, the first listener should have been removed and the
  969. // event should have been fired. Since the listener was removed before the
  970. // event dispatch ran in JS, the first listener should *not* have been
  971. // notified.
  972. EXPECT_EQ(1u, handler()->GetNumEventListenersForTesting(kEventName, context));
  973. EXPECT_EQ("undefined", GetStringPropertyFromObject(context->Global(), context,
  974. "eventFired1"));
  975. EXPECT_EQ("true", GetStringPropertyFromObject(context->Global(), context,
  976. "eventFired2"));
  977. }
  978. // Test that notifications are properly fired for multiple events with the
  979. // same context owner.
  980. TEST_F(APIEventHandlerTest,
  981. TestListenersFromDifferentContextsWithTheSameOwner) {
  982. v8::HandleScope handle_scope(isolate());
  983. v8::Local<v8::Context> context_alpha1 = MainContext();
  984. v8::Local<v8::Context> context_alpha2 = AddContext();
  985. v8::Local<v8::Context> context_beta1 = AddContext();
  986. // Associate two v8::Contexts with the same owner, and a third with a separate
  987. // owner.
  988. auto get_context_owner = [context_alpha1, context_alpha2,
  989. context_beta1](v8::Local<v8::Context> context) {
  990. if (context == context_alpha1 || context == context_alpha2)
  991. return std::string("alpha");
  992. if (context == context_beta1)
  993. return std::string("beta");
  994. ADD_FAILURE();
  995. return std::string();
  996. };
  997. MockEventChangeHandler change_handler;
  998. APIEventHandler handler(change_handler.Get(),
  999. base::BindLambdaForTesting(get_context_owner),
  1000. nullptr);
  1001. const char kEventName[] = "alpha";
  1002. v8::Local<v8::Object> event_alpha1 = handler.CreateEventInstance(
  1003. kEventName, false, true, binding::kNoListenerMax, true, context_alpha1);
  1004. ASSERT_FALSE(event_alpha1.IsEmpty());
  1005. v8::Local<v8::Object> event_alpha2 = handler.CreateEventInstance(
  1006. kEventName, false, true, binding::kNoListenerMax, true, context_alpha2);
  1007. ASSERT_FALSE(event_alpha2.IsEmpty());
  1008. v8::Local<v8::Object> event_beta1 = handler.CreateEventInstance(
  1009. kEventName, false, true, binding::kNoListenerMax, true, context_beta1);
  1010. ASSERT_FALSE(event_beta1.IsEmpty());
  1011. // Add a listener to the first event. The APIEventHandler should notify
  1012. // since it's a change in state (no listeners -> listeners).
  1013. v8::Local<v8::Function> listener_alpha1 =
  1014. FunctionFromString(context_alpha1, "(function() {})");
  1015. EXPECT_CALL(change_handler,
  1016. Run(kEventName,
  1017. binding::EventListenersChanged::
  1018. kFirstUnfilteredListenerForContextOwnerAdded,
  1019. nullptr, true, context_alpha1))
  1020. .Times(1);
  1021. AddListener(context_alpha1, listener_alpha1, event_alpha1);
  1022. ::testing::Mock::VerifyAndClearExpectations(&change_handler);
  1023. // Adding a listener to the same event in a different context that is still
  1024. // associated with the same owner should fire a notification for the context,
  1025. // but not the context owner.
  1026. EXPECT_CALL(change_handler, Run(kEventName,
  1027. binding::EventListenersChanged::
  1028. kFirstUnfilteredListenerForContextAdded,
  1029. nullptr, true, context_alpha2))
  1030. .Times(1);
  1031. v8::Local<v8::Function> listener_alpha2 =
  1032. FunctionFromString(context_alpha2, "(function() {})");
  1033. AddListener(context_alpha2, listener_alpha2, event_alpha2);
  1034. ::testing::Mock::VerifyAndClearExpectations(&change_handler);
  1035. // Adding a listener in a separate context should fire a notification.
  1036. v8::Local<v8::Function> listener_beta1 =
  1037. FunctionFromString(context_alpha1, "(function() {})");
  1038. EXPECT_CALL(change_handler,
  1039. Run(kEventName,
  1040. binding::EventListenersChanged::
  1041. kFirstUnfilteredListenerForContextOwnerAdded,
  1042. nullptr, true, context_beta1))
  1043. .Times(1);
  1044. AddListener(context_beta1, listener_beta1, event_beta1);
  1045. ::testing::Mock::VerifyAndClearExpectations(&change_handler);
  1046. // Removing one of the listeners from the alpha context should notify about
  1047. // the context, but not the context owner (since there are multiple listeners
  1048. // for the context owner).
  1049. EXPECT_CALL(change_handler, Run(kEventName,
  1050. binding::EventListenersChanged::
  1051. kLastUnfilteredListenerForContextRemoved,
  1052. nullptr, true, context_alpha1))
  1053. .Times(1);
  1054. RemoveListener(context_alpha1, listener_alpha1, event_alpha1);
  1055. ::testing::Mock::VerifyAndClearExpectations(&change_handler);
  1056. // Removing the final listener should fire a notification for the context
  1057. // owner.
  1058. EXPECT_CALL(change_handler,
  1059. Run(kEventName,
  1060. binding::EventListenersChanged::
  1061. kLastUnfilteredListenerForContextOwnerRemoved,
  1062. nullptr, true, context_alpha2))
  1063. .Times(1);
  1064. RemoveListener(context_alpha2, listener_alpha2, event_alpha2);
  1065. ::testing::Mock::VerifyAndClearExpectations(&change_handler);
  1066. // And removing the only listener for the beta context should fire a
  1067. // notification.
  1068. EXPECT_CALL(change_handler,
  1069. Run(kEventName,
  1070. binding::EventListenersChanged::
  1071. kLastUnfilteredListenerForContextOwnerRemoved,
  1072. nullptr, true, context_beta1))
  1073. .Times(1);
  1074. RemoveListener(context_beta1, listener_beta1, event_beta1);
  1075. ::testing::Mock::VerifyAndClearExpectations(&change_handler);
  1076. }
  1077. } // namespace extensions