|
12 | 12 | #include <react/renderer/core/EventPipe.h> |
13 | 13 | #include <react/renderer/core/EventQueueProcessor.h> |
14 | 14 | #include <react/renderer/core/EventTarget.h> |
| 15 | +#include <react/renderer/core/InstanceHandle.h> |
15 | 16 | #include <react/renderer/core/ShadowNodeFamily.h> |
16 | 17 | #include <react/renderer/core/StatePipe.h> |
17 | 18 | #include <react/renderer/core/ValueFactoryEventPayload.h> |
18 | 19 |
|
19 | 20 | #include <memory> |
| 21 | +#include <stdexcept> |
20 | 22 | #include <string_view> |
21 | 23 |
|
22 | 24 | namespace facebook::react { |
@@ -157,4 +159,50 @@ TEST_F(EventQueueProcessorTest, alwaysDiscreteEvent) { |
157 | 159 | EXPECT_EQ(eventPriorities_[0], ReactEventPriority::Discrete); |
158 | 160 | } |
159 | 161 |
|
| 162 | +TEST_F(EventQueueProcessorTest, releasesEventTargetsWhenDispatchThrows) { |
| 163 | + // Set up an enabled EventTarget so that flushEvents() will retain a strong |
| 164 | + // JSI reference to its instance handle. |
| 165 | + auto object = jsi::Object(*runtime_); |
| 166 | + auto instanceHandle = std::make_shared<InstanceHandle>( |
| 167 | + *runtime_, jsi::Value(*runtime_, object), 1); |
| 168 | + auto eventTarget = |
| 169 | + std::make_shared<EventTarget>(std::move(instanceHandle), 41); |
| 170 | + eventTarget->setEnabled(true); |
| 171 | + |
| 172 | + // An event pipe that throws, simulating a JS exception during dispatch. |
| 173 | + auto throwingEventPipe = [](jsi::Runtime& /*runtime*/, |
| 174 | + const EventTarget* /*eventTarget*/, |
| 175 | + const std::string& /*type*/, |
| 176 | + ReactEventPriority /*priority*/, |
| 177 | + const EventPayload& /*payload*/, |
| 178 | + HighResTimeStamp /*eventTimestamp*/) { |
| 179 | + throw std::runtime_error("dispatch failed"); |
| 180 | + }; |
| 181 | + auto dummyEventPipeConclusion = [](jsi::Runtime& /*runtime*/) {}; |
| 182 | + auto dummyStatePipe = [](const StateUpdate& /*stateUpdate*/) {}; |
| 183 | + auto mockEventLogger = std::make_shared<MockEventLogger>(); |
| 184 | + |
| 185 | + auto processor = EventQueueProcessor( |
| 186 | + throwingEventPipe, |
| 187 | + dummyEventPipeConclusion, |
| 188 | + dummyStatePipe, |
| 189 | + mockEventLogger); |
| 190 | + |
| 191 | + EXPECT_THROW( |
| 192 | + processor.flushEvents( |
| 193 | + *runtime_, |
| 194 | + {RawEvent( |
| 195 | + "onThrow", |
| 196 | + std::make_shared<ValueFactoryEventPayload>(dummyValueFactory_), |
| 197 | + eventTarget, |
| 198 | + {}, |
| 199 | + RawEvent::Category::Discrete)}), |
| 200 | + std::runtime_error); |
| 201 | + |
| 202 | + // The strong JSI reference acquired by retain() must have been released even |
| 203 | + // though dispatch threw, so the instance handle is no longer reachable |
| 204 | + // through the EventTarget. |
| 205 | + EXPECT_TRUE(eventTarget->getInstanceHandle(*runtime_).isNull()); |
| 206 | +} |
| 207 | + |
160 | 208 | } // namespace facebook::react |
0 commit comments