ReloadInstance async task and InstanceLoaded event were not correctly reporting failures (#9224)

* ReloadInstance async task and InstanceLoaded event were not correctly reporting failures

* Change files

* Add another test

* yarn format

* ignore syntax error file
This commit is contained in:
Andrew Coates 2021-12-02 09:22:44 -08:00 коммит произвёл GitHub
Родитель fe53f11762
Коммит 403da047bc
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
7 изменённых файлов: 89 добавлений и 8 удалений

Просмотреть файл

@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "ReloadInstance async task and InstanceLoaded event were not correctly reporting failures",
"packageName": "react-native-windows",
"email": "30809111+acoates-ms@users.noreply.github.com",
"dependentChangeType": "patch"
}

Просмотреть файл

@ -8,6 +8,7 @@
/local-cli/lib
/local-cli/lib-commonjs
/packages
/Microsoft.ReactNative.IntegrationTests/SyntaxError.js
/ReactCopies
/RNTester.d.ts
/src/rntypes

Просмотреть файл

@ -112,6 +112,65 @@ TEST_CLASS (ReactNativeHostTests) {
TestEventService::ObserveEvents({TestEvent{"InstanceLoaded::Completed", nullptr}});
}
TEST_METHOD(LoadInstance_FiresInstanceLoaded_Success) {
TestEventService::Initialize();
auto options = TestReactNativeHostHolder::Options{};
auto reactNativeHost = TestReactNativeHostHolder(L"ReactNativeHostTests", [](ReactNativeHost const &host) noexcept {
host.InstanceSettings().InstanceLoaded(
[](auto const &, winrt::Microsoft::ReactNative::IInstanceLoadedEventArgs args) noexcept {
if (args.Failed()) {
TestEventService::LogEvent("InstanceLoaded::Failed", nullptr);
} else {
TestEventService::LogEvent("InstanceLoaded::Success", nullptr);
}
});
});
TestEventService::ObserveEvents({TestEvent{"InstanceLoaded::Success", nullptr}});
}
TEST_METHOD(LoadBundleWithError_FiresInstanceLoaded_Failed) {
TestEventService::Initialize();
auto options = TestReactNativeHostHolder::Options{};
auto reactNativeHost = TestReactNativeHostHolder(L"SyntaxError", [](ReactNativeHost const &host) noexcept {
host.InstanceSettings().InstanceLoaded(
[](auto const &, winrt::Microsoft::ReactNative::IInstanceLoadedEventArgs args) noexcept {
if (args.Failed()) {
TestEventService::LogEvent("InstanceLoaded::Failed", nullptr);
} else {
TestEventService::LogEvent("InstanceLoaded::Success", nullptr);
}
});
});
TestEventService::ObserveEvents({TestEvent{"InstanceLoaded::Failed", nullptr}});
}
TEST_METHOD(LoadBundleWithError_ReloadInstance_Fails) {
TestEventService::Initialize();
auto options = TestReactNativeHostHolder::Options{};
options.LoadInstance = false;
auto reactNativeHost = TestReactNativeHostHolder(
L"SyntaxError",
[](ReactNativeHost const &host) noexcept {
host.ReloadInstance().Completed([](auto const &, winrt::Windows::Foundation::AsyncStatus status) mutable {
if (status == winrt::Windows::Foundation::AsyncStatus::Completed) {
TestEventService::LogEvent("InstanceLoaded::Completed", nullptr);
} else if (status == winrt::Windows::Foundation::AsyncStatus::Canceled) {
TestEventService::LogEvent("InstanceLoaded::Canceled", nullptr);
} else {
TestEventService::LogEvent("InstanceLoaded::Failed", nullptr);
}
});
},
std::move(options));
TestEventService::ObserveEvents({TestEvent{"InstanceLoaded::Canceled", nullptr}});
}
};
} // namespace ReactNativeIntegrationTests

Просмотреть файл

@ -0,0 +1,3 @@
// Bundle with syntax error to test bundle load failures
global.foo(();

Просмотреть файл

@ -379,8 +379,13 @@ Mso::Future<void> ReactHost::LoadInQueue(ReactOptions &&options) noexcept {
}
}
return whenLoaded.AsFuture().Then(m_executor, [this](Mso::Maybe<void> && /*value*/) noexcept {
return whenLoaded.AsFuture().Then(m_executor, [this](Mso::Maybe<void> &&value) noexcept {
std::vector<Mso::Future<void>> loadCompletionList;
if (value.IsError()) {
return Mso::MakeFailedFuture<void>(std::move(value.TakeError()));
}
ForEachViewHost([&loadCompletionList](auto &viewHost) noexcept {
loadCompletionList.push_back(viewHost.UpdateViewInstanceInQueue());
});

Просмотреть файл

@ -216,9 +216,11 @@ ReactInstanceWin::ReactInstanceWin(
m_whenLoaded.AsFuture()
.Then<Mso::Executors::Inline>(
[onLoaded = m_options.OnInstanceLoaded, reactContext = m_reactContext](Mso::Maybe<void> &&value) noexcept {
auto errCode = value.IsError() ? value.TakeError() : Mso::ErrorCode();
if (onLoaded) {
onLoaded.Get()->Invoke(reactContext, value.IsError() ? value.TakeError() : Mso::ErrorCode());
onLoaded.Get()->Invoke(reactContext, errCode);
}
return Mso::Maybe<void>(errCode);
})
.Then(Queue(), [whenLoaded = std::move(whenLoaded)](Mso::Maybe<void> &&value) noexcept {
whenLoaded.SetValue(std::move(value));
@ -529,7 +531,9 @@ void ReactInstanceWin::LoadJSBundles() noexcept {
try {
instanceWrapper->loadBundleSync(Mso::Copy(strongThis->JavaScriptBundleFile()));
strongThis->OnReactInstanceLoaded(Mso::ErrorCode{});
if (strongThis->State() != ReactInstanceState::HasError) {
strongThis->OnReactInstanceLoaded(Mso::ErrorCode{});
}
} catch (...) {
strongThis->OnReactInstanceLoaded(Mso::ExceptionErrorProvider().MakeErrorCode(std::current_exception()));
}

Просмотреть файл

@ -27,18 +27,20 @@ struct AsyncActionFutureAdapter : winrt::implements<
if (strongThis->m_status == AsyncStatus::Started) {
if (result.IsValue()) {
strongThis->m_status = AsyncStatus::Completed;
if (strongThis->m_completedAssigned) {
handler = std::move(strongThis->m_completed);
}
} else {
strongThis->m_status = AsyncStatus::Error;
strongThis->m_error = result.GetError();
strongThis->m_status = Mso::CancellationErrorProvider().TryGetErrorInfo(strongThis->m_error, false)
? AsyncStatus::Canceled
: AsyncStatus::Error;
}
if (strongThis->m_completedAssigned) {
handler = std::move(strongThis->m_completed);
}
}
}
if (handler) {
invoke(handler, *strongThis, AsyncStatus::Completed);
invoke(handler, *strongThis, strongThis->m_status);
}
}
});