diff --git a/.ado/build-template.yml b/.ado/build-template.yml
index 69a0c6f6556..43a3cb1dccd 100644
--- a/.ado/build-template.yml
+++ b/.ado/build-template.yml
@@ -265,31 +265,20 @@ extends:
timeoutInMinutes: 360 # CodeQL requires 3x usual build timeout
variables:
- template: .ado/variables/windows.yml@self
- # Enable if any issues RNTesterIntegrationTests::* become unstable.
+ # Enable if any issues RNTesterHeadlessTests::* become unstable.
- name: Desktop.IntegrationTests.SkipRNTester
value: false
- #5059 - Disable failing or intermittent tests (IntegrationTestHarness,WebSocket,Logging).
#10732 - WebSocketIntegrationTest::SendReceiveSsl fails on Windows Server 2022.
#12714 - Disable for first deployment of test website.
- #14217 - Reneable RNTesterIntegrationTests
- name: Desktop.IntegrationTests.Filter
value: >
- (FullyQualifiedName!=RNTesterIntegrationTests::IntegrationTestHarness)&
- (FullyQualifiedName!=RNTesterIntegrationTests::WebSocket)&
- (FullyQualifiedName!=RNTesterIntegrationTests::WebSocketBlob)&
- (FullyQualifiedName!=RNTesterIntegrationTests::WebSocketMultipleSend)&
(FullyQualifiedName!=Microsoft::React::Test::WebSocketIntegrationTest::ConnectClose)&
(FullyQualifiedName!=Microsoft::React::Test::WebSocketIntegrationTest::ConnectNoClose)&
(FullyQualifiedName!=Microsoft::React::Test::WebSocketIntegrationTest::SendReceiveClose)&
(FullyQualifiedName!=Microsoft::React::Test::WebSocketIntegrationTest::SendConsecutive)&
(FullyQualifiedName!=Microsoft::React::Test::WebSocketIntegrationTest::SendReceiveLargeMessage)&
(FullyQualifiedName!=Microsoft::React::Test::WebSocketIntegrationTest::SendReceiveSsl)&
- (FullyQualifiedName!=Microsoft::React::Test::HttpOriginPolicyIntegrationTest)&
- (FullyQualifiedName!=RNTesterIntegrationTests::Dummy)&
- (FullyQualifiedName!=RNTesterIntegrationTests::Fetch)&
- (FullyQualifiedName!=RNTesterIntegrationTests::XHRSample)&
- (FullyQualifiedName!=RNTesterIntegrationTests::Blob)&
- (FullyQualifiedName!=RNTesterIntegrationTests::Logging)
+ (FullyQualifiedName!=Microsoft::React::Test::HttpOriginPolicyIntegrationTest)
#6799 - HostFunctionTest, HostObjectProtoTest crash under JSI/V8;
# PreparedJavaScriptSourceTest asserts/fails under JSI/ChakraCore
- name: Desktop.UnitTests.Filter
diff --git a/.ado/jobs/desktop-single.yml b/.ado/jobs/desktop-single.yml
index 38c41c33fd3..c3cafc12aa8 100644
--- a/.ado/jobs/desktop-single.yml
+++ b/.ado/jobs/desktop-single.yml
@@ -21,27 +21,17 @@ parameters:
- Continuous
steps:
+ - template: ../templates/checkout-shallow.yml
+
# Set up IIS for integration tests
- pwsh: |
Install-WindowsFeature -Name Web-Server, Web-Scripting-Tools
displayName: Install IIS
- pwsh: |
- function Invoke-WebRequestWithRetry($Uri, $OutFile, $MaxRetries = 3) {
- for ($i = 1; $i -le $MaxRetries; $i++) {
- try {
- Write-Host "Downloading $OutFile (attempt $i of $MaxRetries)"
- Invoke-WebRequest -Uri $Uri -OutFile $OutFile
- return
- } catch {
- Write-Host "Attempt $i failed: $_"
- if ($i -eq $MaxRetries) { throw }
- Start-Sleep -Seconds (5 * $i)
- }
- }
- }
+ $DownloadScript = "$(Build.SourcesDirectory)\vnext\Scripts\Tfs\Invoke-WebRequestWithRetry.ps1"
- Invoke-WebRequestWithRetry `
+ & $DownloadScript `
-Uri 'https://download.visualstudio.microsoft.com/download/pr/20598243-c38f-4538-b2aa-af33bc232f80/ea9b2ca232f59a6fdc84b7a31da88464/dotnet-hosting-8.0.3-win.exe' `
-OutFile dotnet-hosting-8.0.3-win.exe
@@ -49,7 +39,7 @@ steps:
Start-Process -Wait -FilePath .\dotnet-hosting-8.0.3-win.exe -ArgumentList '/INSTALL', '/QUIET', '/NORESTART'
Write-Host 'Installed .NET hosting bundle'
- Invoke-WebRequestWithRetry `
+ & $DownloadScript `
-Uri 'https://download.visualstudio.microsoft.com/download/pr/f2ec926e-0d98-4a8b-8c70-722ccc2ca0e5/b59941b0c60f16421679baafdb7e9338/dotnet-sdk-7.0.407-win-x64.exe' `
-OutFile dotnet-sdk-7.0.407-win-x64.exe
@@ -58,7 +48,17 @@ steps:
Write-Host 'Installed .NET 7 SDK'
displayName: Install the .NET Core Hosting Bundle
- - template: ../templates/checkout-shallow.yml
+ - pwsh: |
+ $DownloadScript = "$(Build.SourcesDirectory)\vnext\Scripts\Tfs\Invoke-WebRequestWithRetry.ps1"
+
+ & $DownloadScript `
+ -Uri 'https://aka.ms/windowsappsdk/1.8/latest/windowsappruntimeinstall-x64.exe' `
+ -OutFile windowsappruntimeinstall-x64.exe
+
+ Write-Host 'Installing Windows App SDK Runtime'
+ Start-Process -Wait -FilePath .\windowsappruntimeinstall-x64.exe -ArgumentList '--quiet'
+ Write-Host 'Installed Windows App SDK Runtime'
+ displayName: Install Windows App SDK Runtime
- template: ../templates/prepare-js-env.yml
@@ -72,7 +72,7 @@ steps:
- ${{ if eq(variables['Desktop.IntegrationTests.SkipRNTester'], true) }}:
- pwsh: |
- $newValue = '(FullyQualifiedName!~RNTesterIntegrationTests::)&' + "$(Desktop.IntegrationTests.Filter)"
+ $newValue = '(FullyQualifiedName!~Microsoft::React::Test::RNTesterHeadlessTests::)&' + "$(Desktop.IntegrationTests.Filter)"
Write-Host "##vso[task.setvariable variable=Desktop.IntegrationTests.Filter]$newValue"
displayName: Update Desktop.IntegrationTests.Filter to exclude RNTester integration tests
diff --git a/Directory.Build.targets b/Directory.Build.targets
index a8b078a0544..806c6058f3d 100644
--- a/Directory.Build.targets
+++ b/Directory.Build.targets
@@ -108,6 +108,8 @@
RnwNewArch;
UseFabric;
FollyDir;
+ IncludeFabricInterface;
+ UseFabric;
YogaDir;
WinVer;
" />
diff --git a/change/react-native-windows-e83b01b1-0133-47da-8a8a-c88a6c16398b.json b/change/react-native-windows-e83b01b1-0133-47da-8a8a-c88a6c16398b.json
new file mode 100644
index 00000000000..2126bd891be
--- /dev/null
+++ b/change/react-native-windows-e83b01b1-0133-47da-8a8a-c88a6c16398b.json
@@ -0,0 +1,7 @@
+{
+ "type": "prerelease",
+ "comment": "Re-introduce Desktop integration tests",
+ "packageName": "react-native-windows",
+ "email": "julio.rocha@microsoft.com",
+ "dependentChangeType": "patch"
+}
diff --git a/packages/@rnw-scripts/unbroken/bin.js b/packages/@rnw-scripts/unbroken/bin.js
old mode 100644
new mode 100755
diff --git a/vnext/Desktop.DLL/React.Windows.Desktop.DLL.vcxproj b/vnext/Desktop.DLL/React.Windows.Desktop.DLL.vcxproj
index 2cc3f9e5700..e3689a7623c 100644
--- a/vnext/Desktop.DLL/React.Windows.Desktop.DLL.vcxproj
+++ b/vnext/Desktop.DLL/React.Windows.Desktop.DLL.vcxproj
@@ -179,7 +179,7 @@
-
+
diff --git a/vnext/Desktop.IntegrationTests/Modules/TestAppState.cpp b/vnext/Desktop.IntegrationTests/Modules/TestAppState.cpp
new file mode 100644
index 00000000000..57626154120
--- /dev/null
+++ b/vnext/Desktop.IntegrationTests/Modules/TestAppState.cpp
@@ -0,0 +1,24 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#include "TestAppState.h"
+
+namespace Microsoft::React::Test {
+
+void AppState::Initialize(winrt::Microsoft::ReactNative::ReactContext const &) noexcept {}
+
+void AppState::GetCurrentAppState(
+ std::function const &success,
+ std::function const &) noexcept {
+ success({.app_state = "active"});
+}
+
+void AppState::AddListener(std::string) noexcept {}
+
+void AppState::RemoveListeners(double) noexcept {}
+
+::Microsoft::ReactNativeSpecs::AppStateSpec_AppStateConstants AppState::GetConstants() noexcept {
+ return {.initialAppState = "active"};
+}
+
+} // namespace Microsoft::React::Test
diff --git a/vnext/Desktop.IntegrationTests/Modules/TestAppState.h b/vnext/Desktop.IntegrationTests/Modules/TestAppState.h
new file mode 100644
index 00000000000..394179f54ac
--- /dev/null
+++ b/vnext/Desktop.IntegrationTests/Modules/TestAppState.h
@@ -0,0 +1,33 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#pragma once
+
+#include
+#include
+
+namespace Microsoft::React::Test {
+
+REACT_MODULE(AppState)
+struct AppState {
+ using ModuleSpec = ::Microsoft::ReactNativeSpecs::AppStateSpec;
+
+ REACT_INIT(Initialize)
+ void Initialize(winrt::Microsoft::ReactNative::ReactContext const &) noexcept;
+
+ REACT_METHOD(GetCurrentAppState, L"getCurrentAppState")
+ void GetCurrentAppState(
+ std::function const &success,
+ std::function const &) noexcept;
+
+ REACT_METHOD(AddListener, L"addListener")
+ void AddListener(std::string) noexcept;
+
+ REACT_METHOD(RemoveListeners, L"removeListeners")
+ void RemoveListeners(double) noexcept;
+
+ REACT_GET_CONSTANTS(GetConstants)
+ ::Microsoft::ReactNativeSpecs::AppStateSpec_AppStateConstants GetConstants() noexcept;
+};
+
+} // namespace Microsoft::React::Test
diff --git a/vnext/Desktop.IntegrationTests/Modules/TestDeviceInfo.cpp b/vnext/Desktop.IntegrationTests/Modules/TestDeviceInfo.cpp
new file mode 100644
index 00000000000..59b8a201c65
--- /dev/null
+++ b/vnext/Desktop.IntegrationTests/Modules/TestDeviceInfo.cpp
@@ -0,0 +1,22 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#include "TestDeviceInfo.h"
+
+namespace Microsoft::React::Test {
+
+void DeviceInfo::Initialize(winrt::Microsoft::ReactNative::ReactContext const &) noexcept {}
+
+::Microsoft::ReactNativeSpecs::DeviceInfoSpec_DeviceInfoConstants DeviceInfo::GetConstants() noexcept {
+ ::Microsoft::ReactNativeSpecs::DeviceInfoSpec_DeviceInfoConstants constants;
+ ::Microsoft::ReactNativeSpecs::DeviceInfoSpec_DisplayMetrics dm;
+ dm.fontScale = 1;
+ dm.height = 1024;
+ dm.width = 1024;
+ dm.scale = 1;
+ constants.Dimensions.screen = dm;
+ constants.Dimensions.window = dm;
+ return constants;
+}
+
+} // namespace Microsoft::React::Test
diff --git a/vnext/Desktop.IntegrationTests/Modules/TestDeviceInfo.h b/vnext/Desktop.IntegrationTests/Modules/TestDeviceInfo.h
new file mode 100644
index 00000000000..7dfaf40df9e
--- /dev/null
+++ b/vnext/Desktop.IntegrationTests/Modules/TestDeviceInfo.h
@@ -0,0 +1,22 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#pragma once
+
+#include
+#include
+
+namespace Microsoft::React::Test {
+
+REACT_MODULE(DeviceInfo)
+struct DeviceInfo {
+ using ModuleSpec = ::Microsoft::ReactNativeSpecs::DeviceInfoSpec;
+
+ REACT_INIT(Initialize)
+ void Initialize(winrt::Microsoft::ReactNative::ReactContext const &) noexcept;
+
+ REACT_GET_CONSTANTS(GetConstants)
+ ::Microsoft::ReactNativeSpecs::DeviceInfoSpec_DeviceInfoConstants GetConstants() noexcept;
+};
+
+} // namespace Microsoft::React::Test
diff --git a/vnext/Desktop.IntegrationTests/Modules/TestModule.h b/vnext/Desktop.IntegrationTests/Modules/TestModule.h
new file mode 100644
index 00000000000..40a2fa5b93e
--- /dev/null
+++ b/vnext/Desktop.IntegrationTests/Modules/TestModule.h
@@ -0,0 +1,80 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#pragma once
+
+#include
+
+#include
+
+// Standard Library
+#include
+#include
+#include
+
+namespace Microsoft::React::Test {
+
+enum class TestStatus { Pending = 0, Passed, Failed };
+
+REACT_MODULE(TestModule)
+struct TestModule {
+ // Static test signaling - call Reset() before each test.
+ static void Reset() noexcept {
+ ResetEvent(s_completed.get());
+ s_status = TestStatus::Pending;
+ }
+
+ static TestStatus AwaitCompletion(DWORD timeoutMs = INFINITE) noexcept {
+ WaitForSingleObject(s_completed.get(), timeoutMs);
+ return s_status;
+ }
+
+ REACT_INIT(Initialize)
+ void Initialize(winrt::Microsoft::ReactNative::ReactContext const &reactContext) noexcept {
+ m_reactContext = reactContext;
+ }
+
+ REACT_METHOD(MarkTestCompleted, L"markTestCompleted")
+ void MarkTestCompleted() noexcept {
+ MarkTestPassed(true);
+ }
+
+ REACT_METHOD(MarkTestPassed, L"markTestPassed")
+ void MarkTestPassed(bool success) noexcept {
+ s_status = success ? TestStatus::Passed : TestStatus::Failed;
+ SetEvent(s_completed.get());
+ }
+
+ REACT_METHOD(VerifySnapshot, L"verifySnapshot")
+ void VerifySnapshot(std::function const &callback) noexcept {
+ // Snapshot testing is not supported on Windows; always report success.
+ callback(true);
+ }
+
+ REACT_METHOD(SendAppEvent, L"sendAppEvent")
+ void SendAppEvent(std::string name, ::React::JSValue body) noexcept {
+ m_reactContext.EmitJSEvent(L"RCTDeviceEventEmitter", winrt::to_hstring(name), body);
+ }
+
+ REACT_METHOD(ShouldResolve, L"shouldResolve")
+ void ShouldResolve(::React::ReactPromise &&result) noexcept {
+ result.Resolve(1);
+ }
+
+ REACT_METHOD(ShouldReject, L"shouldReject")
+ void ShouldReject(::React::ReactPromise<::React::JSValue> &&result) noexcept {
+ result.Reject(::React::ReactError{});
+ }
+
+ TestStatus Status() const noexcept {
+ return s_status;
+ }
+
+ private:
+ winrt::Microsoft::ReactNative::ReactContext m_reactContext;
+
+ static inline std::atomic s_status{TestStatus::Pending};
+ static inline winrt::handle s_completed{CreateEvent(nullptr, TRUE /*manualReset*/, FALSE /*initialState*/, nullptr)};
+};
+
+} // namespace Microsoft::React::Test
diff --git a/vnext/Desktop.IntegrationTests/RNTesterHeadlessTests.cpp b/vnext/Desktop.IntegrationTests/RNTesterHeadlessTests.cpp
new file mode 100644
index 00000000000..f25eb3cdd4d
--- /dev/null
+++ b/vnext/Desktop.IntegrationTests/RNTesterHeadlessTests.cpp
@@ -0,0 +1,68 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#include
+
+#include
+
+#include
+#include
+
+#include "Modules/TestModule.h"
+#include "TestReactNativeHostHolder.h"
+
+using namespace Microsoft::VisualStudio::CppUnitTestFramework;
+
+namespace msrn = winrt::Microsoft::ReactNative;
+
+namespace Microsoft::React::Test {
+
+TEST_CLASS (RNTesterHeadlessTests) {
+ TEST_CLASS_INITIALIZE(Initialize) {
+ // https://learn.microsoft.com/en-us/windows/windows-app-sdk/api/win32/mddbootstrap/nf-mddbootstrap-mddbootstrapinitialize2
+ winrt::uninit_apartment();
+ winrt::init_apartment(winrt::apartment_type::multi_threaded);
+
+ if (FAILED(MddBootstrapInitialize2(
+ Microsoft::WindowsAppSDK::Release::MajorMinor,
+ Microsoft::WindowsAppSDK::Release::VersionTag,
+ {Microsoft::WindowsAppSDK::Runtime::Version::UInt64},
+ MddBootstrapInitializeOptions::MddBootstrapInitializeOptions_None))) {
+ throw std::exception("Could not initialize Windows App runtime");
+ }
+ }
+
+ TEST_CLASS_CLEANUP(Cleanup) {
+ MddBootstrapShutdown();
+ }
+
+ TEST_METHOD(Dummy) {
+ TestModule::Reset();
+
+ winrt::handle instanceLoadedEvent{CreateEvent(nullptr, TRUE, FALSE, nullptr)};
+ bool instanceFailed{false};
+
+ auto holder = TestReactNativeHostHolder(
+ L"IntegrationTests/DummyTest",
+ [&instanceLoadedEvent, &instanceFailed](msrn::ReactNativeHost const &host) noexcept {
+ host.InstanceSettings().InstanceLoaded(
+ [&instanceLoadedEvent, &instanceFailed](auto const &, msrn::InstanceLoadedEventArgs args) noexcept {
+ instanceFailed = args.Failed();
+ SetEvent(instanceLoadedEvent.get());
+ });
+ });
+
+ // First, wait for instance to load
+ WaitForSingleObject(instanceLoadedEvent.get(), INFINITE);
+ if (instanceFailed) {
+ auto err = holder.GetLastError();
+ auto msg = L"InstanceLoaded reported failure: " + (err.empty() ? L"(no error captured)" : err);
+ Assert::Fail(msg.c_str());
+ }
+
+ auto status = TestModule::AwaitCompletion();
+ Assert::IsTrue(status == TestStatus::Passed, L"Test did not pass (JS did not call markTestPassed within timeout)");
+ }
+};
+
+} // namespace Microsoft::React::Test
diff --git a/vnext/Desktop.IntegrationTests/React.Windows.Desktop.IntegrationTests.vcxproj b/vnext/Desktop.IntegrationTests/React.Windows.Desktop.IntegrationTests.vcxproj
index 36ba1f247a7..69d10e47a67 100644
--- a/vnext/Desktop.IntegrationTests/React.Windows.Desktop.IntegrationTests.vcxproj
+++ b/vnext/Desktop.IntegrationTests/React.Windows.Desktop.IntegrationTests.vcxproj
@@ -79,7 +79,6 @@
FOLLY_NO_CONFIG;
NOMINMAX;
_HAS_AUTO_PTR_ETC;
- RN_PLATFORM=win32;
RN_EXPORT=;
JSI_EXPORT=;
%(PreprocessorDefinitions)
@@ -88,10 +87,13 @@
$(VCInstallDir)UnitTest\include;
"$(ReactNativeWindowsDir)Microsoft.ReactNative";
+ "$(ReactNativeWindowsDir)Microsoft.ReactNative\ReactHost";
"$(ReactNativeWindowsDir)\Shared\tracing";
+ "$(IntDir)\..\React.Windows.Desktop\Generated Files";
%(AdditionalIncludeDirectories)
true
+
$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)
@@ -114,8 +116,15 @@
+
+
+
+
+
+
+
@@ -136,15 +145,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/vnext/Desktop.IntegrationTests/React.Windows.Desktop.IntegrationTests.vcxproj.filters b/vnext/Desktop.IntegrationTests/React.Windows.Desktop.IntegrationTests.vcxproj.filters
index 39ab943e9e0..45c06fc788b 100644
--- a/vnext/Desktop.IntegrationTests/React.Windows.Desktop.IntegrationTests.vcxproj.filters
+++ b/vnext/Desktop.IntegrationTests/React.Windows.Desktop.IntegrationTests.vcxproj.filters
@@ -30,15 +30,36 @@
Source Files\Modules
+
+ Source Files\Modules
+
+
+ Source Files\Modules
+
Integration Tests
+
+ Integration Tests
+
Source Files
Source Files
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
@@ -47,11 +68,32 @@
Header Files\Modules
+
+ Header Files\Modules
+
+
+ Header Files\Modules
+
Header Files
+
+ Header Files
+
Header Files
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files\Modules
+
\ No newline at end of file
diff --git a/vnext/Desktop.IntegrationTests/TestCompositionContext.h b/vnext/Desktop.IntegrationTests/TestCompositionContext.h
new file mode 100644
index 00000000000..134b1a61c81
--- /dev/null
+++ b/vnext/Desktop.IntegrationTests/TestCompositionContext.h
@@ -0,0 +1,216 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#pragma once
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+// Test implementations of the Composition.Experimental interfaces so that
+// Fabric can run in headless (ui-less) integration tests. Every method is a
+// no-op and every property returns a sensible default.
+
+namespace Microsoft::React::Test {
+
+namespace Exp = winrt::Microsoft::ReactNative::Composition::Experimental;
+
+// ---------- IBrush / IDrawingSurfaceBrush ----------
+
+struct TestBrush : winrt::implements {};
+
+struct TestDrawingSurfaceBrush : winrt::implements {
+ void HorizontalAlignmentRatio(float) {}
+ void VerticalAlignmentRatio(float) {}
+ void Stretch(Exp::CompositionStretch) {}
+};
+
+// ---------- IDropShadow ----------
+
+struct TestDropShadow : winrt::implements {
+ void Offset(winrt::Windows::Foundation::Numerics::float3) {}
+ void Opacity(float) {}
+ void BlurRadius(float) {}
+ void Color(winrt::Windows::UI::Color) {}
+ void Mask(Exp::IBrush) {}
+ void SourcePolicy(Exp::CompositionDropShadowSourcePolicy) {}
+};
+
+// ---------- IVisual (shared base for visual mocks) ----------
+
+template
+struct TestVisualBase : winrt::implements {
+ void InsertAt(Exp::IVisual, int32_t) {}
+ void Remove(Exp::IVisual) {}
+ Exp::IVisual GetAt(uint32_t) {
+ return nullptr;
+ }
+ void Opacity(float) {}
+ void Scale(winrt::Windows::Foundation::Numerics::float3) {}
+ void TransformMatrix(winrt::Windows::Foundation::Numerics::float4x4) {}
+ void RotationAngle(float) {}
+ void IsVisible(bool) {}
+ void Size(winrt::Windows::Foundation::Numerics::float2) {}
+ void Offset(winrt::Windows::Foundation::Numerics::float3) {}
+ void Offset(winrt::Windows::Foundation::Numerics::float3, winrt::Windows::Foundation::Numerics::float3) {}
+ void RelativeSizeWithOffset(
+ winrt::Windows::Foundation::Numerics::float2,
+ winrt::Windows::Foundation::Numerics::float2) {}
+ Exp::BackfaceVisibility BackfaceVisibility() {
+ return Exp::BackfaceVisibility::Visible;
+ }
+ void BackfaceVisibility(Exp::BackfaceVisibility) {}
+ winrt::hstring Comment() {
+ return {};
+ }
+ void Comment(winrt::hstring const &) {}
+ void AnimationClass(Exp::AnimationClass) {}
+};
+
+// ---------- ISpriteVisual ----------
+
+struct TestSpriteVisual : TestVisualBase {
+ void Brush(Exp::IBrush) {}
+ void Shadow(Exp::IDropShadow) {}
+};
+
+// ---------- IRoundedRectangleVisual ----------
+
+struct TestRoundedRectangleVisual
+ : TestVisualBase {
+ void Brush(Exp::IBrush) {}
+ void CornerRadius(winrt::Windows::Foundation::Numerics::float2) {}
+ void StrokeBrush(Exp::IBrush) {}
+ void StrokeThickness(float) {}
+};
+
+// ---------- IScrollVisual ----------
+
+struct TestScrollVisual : TestVisualBase {
+ void Brush(Exp::IBrush) {}
+ void ScrollEnabled(bool) {}
+ winrt::event_token ScrollPositionChanged(
+ winrt::Windows::Foundation::EventHandler const &) {
+ return {};
+ }
+ void ScrollPositionChanged(winrt::event_token) {}
+ winrt::event_token ScrollBeginDrag(
+ winrt::Windows::Foundation::EventHandler const &) {
+ return {};
+ }
+ void ScrollBeginDrag(winrt::event_token) {}
+ winrt::event_token ScrollEndDrag(winrt::Windows::Foundation::EventHandler const &) {
+ return {};
+ }
+ void ScrollEndDrag(winrt::event_token) {}
+ winrt::event_token ScrollMomentumBegin(
+ winrt::Windows::Foundation::EventHandler const &) {
+ return {};
+ }
+ void ScrollMomentumBegin(winrt::event_token) {}
+ winrt::event_token ScrollMomentumEnd(
+ winrt::Windows::Foundation::EventHandler const &) {
+ return {};
+ }
+ void ScrollMomentumEnd(winrt::event_token) {}
+ void ContentSize(winrt::Windows::Foundation::Numerics::float2) {}
+ winrt::Windows::Foundation::Numerics::float3 ScrollPosition() {
+ return {};
+ }
+ void ScrollBy(winrt::Windows::Foundation::Numerics::float3, bool) {}
+ void TryUpdatePosition(winrt::Windows::Foundation::Numerics::float3, bool) {}
+ void OnPointerPressed(winrt::Microsoft::ReactNative::Composition::Input::PointerRoutedEventArgs const &) {}
+ void SetDecelerationRate(winrt::Windows::Foundation::Numerics::float3) {}
+ void SetMaximumZoomScale(float) {}
+ void SetMinimumZoomScale(float) {}
+ bool Horizontal() {
+ return false;
+ }
+ void Horizontal(bool) {}
+ void SetSnapPoints(bool, bool, winrt::Windows::Foundation::Collections::IVectorView const &) {}
+ void PagingEnabled(bool) {}
+ void SnapToInterval(float) {}
+ void SnapToAlignment(Exp::SnapPointsAlignment) {}
+};
+
+// ---------- IActivityVisual ----------
+
+struct TestActivityVisual : TestVisualBase {
+ using TestVisualBase::Size; // IVisual::Size(float2)
+ void Size(float) {} // IActivityVisual::Size(float)
+ void Brush(Exp::IBrush) {}
+ void StartAnimation() {}
+ void StopAnimation() {}
+};
+
+// ---------- ICaretVisual ----------
+
+struct TestCaretVisual : winrt::implements {
+ Exp::IVisual InnerVisual() {
+ return winrt::make();
+ }
+ void Size(winrt::Windows::Foundation::Numerics::float2) {}
+ void Position(winrt::Windows::Foundation::Numerics::float2) {}
+ bool IsVisible() {
+ return false;
+ }
+ void IsVisible(bool) {}
+ void Brush(Exp::IBrush) {}
+};
+
+// ---------- IFocusVisual ----------
+
+struct TestFocusVisual : winrt::implements {
+ Exp::IVisual InnerVisual() {
+ return winrt::make();
+ }
+ bool IsFocused() {
+ return false;
+ }
+ void IsFocused(bool) {}
+ float ScaleFactor() {
+ return 1.0f;
+ }
+ void ScaleFactor(float) {}
+};
+
+// ---------- ICompositionContext ----------
+
+struct TestCompositionContext : winrt::implements {
+ Exp::ISpriteVisual CreateSpriteVisual() {
+ return winrt::make();
+ }
+ Exp::IScrollVisual CreateScrollerVisual() {
+ return winrt::make();
+ }
+ Exp::IRoundedRectangleVisual CreateRoundedRectangleVisual() {
+ return winrt::make();
+ }
+ Exp::IActivityVisual CreateActivityVisual() {
+ return winrt::make();
+ }
+ Exp::ICaretVisual CreateCaretVisual() {
+ return winrt::make();
+ }
+ Exp::IFocusVisual CreateFocusVisual() {
+ return winrt::make();
+ }
+ Exp::IDropShadow CreateDropShadow() {
+ return winrt::make();
+ }
+ Exp::IBrush CreateColorBrush(winrt::Windows::UI::Color) {
+ return winrt::make();
+ }
+ Exp::IDrawingSurfaceBrush CreateDrawingSurfaceBrush(
+ winrt::Windows::Foundation::Size,
+ winrt::Windows::Graphics::DirectX::DirectXPixelFormat,
+ winrt::Windows::Graphics::DirectX::DirectXAlphaMode) {
+ return winrt::make();
+ }
+};
+
+} // namespace Microsoft::React::Test
diff --git a/vnext/Desktop.IntegrationTests/TestReactNativeHostHolder.cpp b/vnext/Desktop.IntegrationTests/TestReactNativeHostHolder.cpp
new file mode 100644
index 00000000000..b530ef645cf
--- /dev/null
+++ b/vnext/Desktop.IntegrationTests/TestReactNativeHostHolder.cpp
@@ -0,0 +1,87 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#include "TestReactNativeHostHolder.h"
+
+#include "TestReactPackageProvider.h"
+#include "TestUIDispatcher.h"
+
+#include
+#include
+#include
+#include
+
+#include "TestCompositionContext.h"
+
+namespace Microsoft::React::Test {
+
+msrn::ReactPropertyId PlatformNameOverrideProperty() noexcept {
+ static msrn::ReactPropertyId prop{L"ReactNative.Injection", L"PlatformNameOverride"};
+ return prop;
+}
+
+TestReactNativeHostHolder::TestReactNativeHostHolder(
+ std::wstring_view jsBundle,
+ std::function hostInitializer,
+ Options &&options) noexcept {
+ m_host = winrt::Microsoft::ReactNative::ReactNativeHost{};
+ m_queueController = winrt::Microsoft::UI::Dispatching::DispatcherQueueController::CreateOnDedicatedThread();
+ m_uiDispatcher = winrt::make(m_queueController.DispatcherQueue());
+
+ m_queueController.DispatcherQueue().TryEnqueue([this,
+ jsBundle = std::wstring{jsBundle},
+ hostInitializer = std::move(hostInitializer),
+ options = std::move(options)]() noexcept {
+ auto settings = m_host.InstanceSettings();
+ settings.JavaScriptBundleFile(jsBundle);
+ settings.Properties().Set(msrn::ReactDispatcherHelper::UIDispatcherProperty(), m_uiDispatcher);
+ settings.Properties().Set(PlatformNameOverrideProperty().Handle(), winrt::box_value(L"windows"));
+ settings.UseDeveloperSupport(false);
+ settings.UseFastRefresh(true);
+ settings.UseLiveReload(false);
+ settings.EnableDeveloperMenu(false);
+ settings.PackageProviders().Append(winrt::make());
+
+ // Capture errors for diagnostics
+ settings.NativeLogger([this](msrn::LogLevel level, winrt::hstring const &message) {
+ if (static_cast(level) >= static_cast(msrn::LogLevel::Error)) {
+ std::lock_guard lock(m_errorMutex);
+ if (m_lastError.empty()) {
+ m_lastError = message;
+ }
+ }
+ });
+
+ // Enable Fabric by setting a stub CompositionContext.
+ // In a headless test we have no real compositor, but this is sufficient
+ // for the runtime to choose the Fabric code path.
+ winrt::Microsoft::ReactNative::ReactPropertyBag(settings.Properties())
+ .Set(
+ winrt::Microsoft::ReactNative::ReactPropertyId<
+ winrt::Microsoft::ReactNative::Composition::Experimental::ICompositionContext>{
+ L"ReactNative.Composition", L"CompositionContext"},
+ winrt::make());
+
+ hostInitializer(m_host);
+
+ if (options.LoadInstance) {
+ m_host.LoadInstance();
+ }
+ });
+}
+
+TestReactNativeHostHolder::~TestReactNativeHostHolder() noexcept {
+ m_host.UnloadInstance().get();
+ m_queueController.ShutdownQueueAsync().get();
+}
+
+winrt::Microsoft::ReactNative::ReactNativeHost const &TestReactNativeHostHolder::Host() const noexcept {
+ return m_host;
+}
+
+std::wstring TestReactNativeHostHolder::GetLastError() const noexcept {
+ std::lock_guard lock(m_errorMutex);
+ return m_lastError;
+}
+
+} // namespace Microsoft::React::Test
diff --git a/vnext/Desktop.IntegrationTests/TestReactNativeHostHolder.h b/vnext/Desktop.IntegrationTests/TestReactNativeHostHolder.h
new file mode 100644
index 00000000000..d248339251e
--- /dev/null
+++ b/vnext/Desktop.IntegrationTests/TestReactNativeHostHolder.h
@@ -0,0 +1,40 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#pragma once
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+namespace Microsoft::React::Test {
+
+namespace msrn = winrt::Microsoft::ReactNative;
+
+struct TestReactNativeHostHolder {
+ struct Options {
+ bool LoadInstance = true;
+ };
+
+ TestReactNativeHostHolder(
+ std::wstring_view jsBundle,
+ std::function hostInitializer,
+ Options &&options = {}) noexcept;
+ ~TestReactNativeHostHolder() noexcept;
+
+ winrt::Microsoft::ReactNative::ReactNativeHost const &Host() const noexcept;
+ std::wstring GetLastError() const noexcept;
+
+ private:
+ winrt::Microsoft::ReactNative::ReactNativeHost m_host{nullptr};
+ winrt::Microsoft::UI::Dispatching::DispatcherQueueController m_queueController{nullptr};
+ msrn::IReactDispatcher m_uiDispatcher{nullptr};
+ mutable std::mutex m_errorMutex;
+ std::wstring m_lastError;
+};
+
+} // namespace Microsoft::React::Test
diff --git a/vnext/Desktop.IntegrationTests/TestReactPackageProvider.cpp b/vnext/Desktop.IntegrationTests/TestReactPackageProvider.cpp
new file mode 100644
index 00000000000..951ed85de69
--- /dev/null
+++ b/vnext/Desktop.IntegrationTests/TestReactPackageProvider.cpp
@@ -0,0 +1,18 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#include "TestReactPackageProvider.h"
+
+#include "Modules/TestAppState.h"
+#include "Modules/TestDeviceInfo.h"
+#include "Modules/TestModule.h"
+
+namespace Microsoft::React::Test {
+
+void TestReactPackageProvider::CreatePackage(msrn::IReactPackageBuilder const &packageBuilder) noexcept {
+ packageBuilder.AddTurboModule(L"DeviceInfo", winrt::Microsoft::ReactNative::MakeModuleProvider());
+ packageBuilder.AddTurboModule(L"AppState", winrt::Microsoft::ReactNative::MakeModuleProvider());
+ winrt::Microsoft::ReactNative::TryAddAttributedModule(packageBuilder, L"TestModule", true);
+}
+
+} // namespace Microsoft::React::Test
diff --git a/vnext/Desktop.IntegrationTests/TestReactPackageProvider.h b/vnext/Desktop.IntegrationTests/TestReactPackageProvider.h
new file mode 100644
index 00000000000..f464d8c0145
--- /dev/null
+++ b/vnext/Desktop.IntegrationTests/TestReactPackageProvider.h
@@ -0,0 +1,17 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#pragma once
+
+#include
+#include
+
+namespace Microsoft::React::Test {
+
+namespace msrn = winrt::Microsoft::ReactNative;
+
+struct TestReactPackageProvider : winrt::implements {
+ void CreatePackage(msrn::IReactPackageBuilder const &packageBuilder) noexcept;
+};
+
+} // namespace Microsoft::React::Test
diff --git a/vnext/Desktop.IntegrationTests/TestTypeDependencies.dgml b/vnext/Desktop.IntegrationTests/TestTypeDependencies.dgml
new file mode 100644
index 00000000000..c7d8289ba56
--- /dev/null
+++ b/vnext/Desktop.IntegrationTests/TestTypeDependencies.dgml
@@ -0,0 +1,125 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/vnext/Desktop.IntegrationTests/TestUIDispatcher.cpp b/vnext/Desktop.IntegrationTests/TestUIDispatcher.cpp
new file mode 100644
index 00000000000..0101c709ae5
--- /dev/null
+++ b/vnext/Desktop.IntegrationTests/TestUIDispatcher.cpp
@@ -0,0 +1,21 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#include "TestUIDispatcher.h"
+
+namespace Microsoft::React::Test {
+
+TestUIDispatcher::TestUIDispatcher(winrt::Microsoft::UI::Dispatching::DispatcherQueue const &dispatcherQueue)
+ : m_dispatcherQueue{dispatcherQueue} {
+ m_dispatcherQueue.TryEnqueue([self = get_strong()]() noexcept { self->m_threadId = GetCurrentThreadId(); });
+}
+
+bool TestUIDispatcher::HasThreadAccess() {
+ return m_threadId == GetCurrentThreadId();
+}
+
+void TestUIDispatcher::Post(msrn::ReactDispatcherCallback const &callback) {
+ m_dispatcherQueue.TryEnqueue([callback]() noexcept { callback(); });
+}
+
+} // namespace Microsoft::React::Test
diff --git a/vnext/Desktop.IntegrationTests/TestUIDispatcher.h b/vnext/Desktop.IntegrationTests/TestUIDispatcher.h
new file mode 100644
index 00000000000..92123efb280
--- /dev/null
+++ b/vnext/Desktop.IntegrationTests/TestUIDispatcher.h
@@ -0,0 +1,26 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#pragma once
+
+#include
+
+#include
+#include
+
+namespace Microsoft::React::Test {
+
+namespace msrn = winrt::Microsoft::ReactNative;
+
+struct TestUIDispatcher : public winrt::implements {
+ TestUIDispatcher(winrt::Microsoft::UI::Dispatching::DispatcherQueue const &dispatcherQueue);
+
+ bool HasThreadAccess();
+ void Post(msrn::ReactDispatcherCallback const &callback);
+
+ private:
+ winrt::Microsoft::UI::Dispatching::DispatcherQueue m_dispatcherQueue;
+ DWORD m_threadId{0};
+};
+
+} // namespace Microsoft::React::Test
diff --git a/vnext/Desktop.IntegrationTests/WinRTActivationShims.cpp b/vnext/Desktop.IntegrationTests/WinRTActivationShims.cpp
new file mode 100644
index 00000000000..548229bab7e
--- /dev/null
+++ b/vnext/Desktop.IntegrationTests/WinRTActivationShims.cpp
@@ -0,0 +1,68 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+// This file provides local implementations for WinRT static methods and
+// constructors that are declared by the CppWinRT-generated headers with
+// CppWinRTOptimized=true. In that mode, cppwinrt emits non-inline
+// declarations expecting the symbols to be supplied by the producing DLL's
+// import library. When those symbols are intentionally excluded from the
+// DLL's DEF file, the linker cannot resolve them.
+//
+// The implementations below obtain activation factories directly from the
+// react-native-win32.dll via its DllGetActivationFactory export. This
+// bypasses RoGetActivationFactory and therefore does not require manifest
+// or activation-context registration.
+
+#include
+#include
+#include
+#include
+
+namespace {
+
+using DllGetActivationFactory_t = HRESULT(WINAPI *)(HSTRING, ::IActivationFactory **);
+
+DllGetActivationFactory_t GetDllGetActivationFactory() noexcept {
+ static auto pfn = reinterpret_cast(
+ ::GetProcAddress(::GetModuleHandleW(L"react-native-win32.dll"), "DllGetActivationFactory"));
+ return pfn;
+}
+
+template
+TFactory GetFactory(std::wstring_view className) {
+ winrt::hstring name{className};
+ winrt::com_ptr<::IActivationFactory> factory;
+ winrt::check_hresult(GetDllGetActivationFactory()(static_cast(winrt::get_abi(name)), factory.put()));
+ return factory.as();
+}
+
+} // anonymous namespace
+
+namespace winrt::Microsoft::ReactNative {
+
+// ReactPropertyBagHelper statics -----------------------------------------
+
+IReactPropertyNamespace ReactPropertyBagHelper::GetNamespace(param::hstring const &namespaceName) {
+ static auto factory = GetFactory(winrt::name_of());
+ return factory.GetNamespace(namespaceName);
+}
+
+IReactPropertyName ReactPropertyBagHelper::GetName(IReactPropertyNamespace const &ns, param::hstring const &localName) {
+ static auto factory = GetFactory(winrt::name_of());
+ return factory.GetName(ns, localName);
+}
+
+// ReactDispatcherHelper statics ------------------------------------------
+
+IReactPropertyName ReactDispatcherHelper::UIDispatcherProperty() {
+ static auto factory = GetFactory(winrt::name_of());
+ return factory.UIDispatcherProperty();
+}
+
+// ReactNativeHost default constructor ------------------------------------
+
+ReactNativeHost::ReactNativeHost()
+ : ReactNativeHost(GetFactory(winrt::name_of())
+ .ActivateInstance()) {}
+
+} // namespace winrt::Microsoft::ReactNative
diff --git a/vnext/Desktop.IntegrationTests/packages.experimentalwinui3.lock.json b/vnext/Desktop.IntegrationTests/packages.experimentalwinui3.lock.json
index e9f4f7afb6d..3f0c369c07c 100644
--- a/vnext/Desktop.IntegrationTests/packages.experimentalwinui3.lock.json
+++ b/vnext/Desktop.IntegrationTests/packages.experimentalwinui3.lock.json
@@ -8,6 +8,12 @@
"resolved": "1.84.0",
"contentHash": "4el2YP3cNJDVFPdzOso+LxGvdWP2rHxML4siq8VdonNypW2m4q503tHfCj6vK0L1UfxioE2hpFGb4ITEua73tg=="
},
+ "Microsoft.JavaScript.Hermes": {
+ "type": "Direct",
+ "requested": "[0.0.0-2512.22001-bc3d0ed7, )",
+ "resolved": "0.0.0-2512.22001-bc3d0ed7",
+ "contentHash": "aMuCKrIwkCAnT56+oKqmxgfIaAHlKRVt8IiG/jtMbG01QH1mLPwL7wP89jRMsYSJzikW96trqgpUllZZa3O+Qw=="
+ },
"Microsoft.Windows.CppWinRT": {
"type": "Direct",
"requested": "[2.0.230706.1, )",
@@ -25,11 +31,6 @@
"resolved": "1.1.1",
"contentHash": "AT3HlgTjsqHnWpBHSNeR0KxbLZD7bztlZVj7I8vgeYG9SYqbeFGh0TM/KVtC6fg53nrWHl3VfZFvb5BiQFcY6Q=="
},
- "Microsoft.JavaScript.Hermes": {
- "type": "Transitive",
- "resolved": "0.0.0-2512.22001-bc3d0ed7",
- "contentHash": "aMuCKrIwkCAnT56+oKqmxgfIaAHlKRVt8IiG/jtMbG01QH1mLPwL7wP89jRMsYSJzikW96trqgpUllZZa3O+Qw=="
- },
"Microsoft.SourceLink.Common": {
"type": "Transitive",
"resolved": "1.1.1",
diff --git a/vnext/Desktop.IntegrationTests/packages.lock.json b/vnext/Desktop.IntegrationTests/packages.lock.json
index 10dfa3dfac0..f9a9523f5fd 100644
--- a/vnext/Desktop.IntegrationTests/packages.lock.json
+++ b/vnext/Desktop.IntegrationTests/packages.lock.json
@@ -8,6 +8,12 @@
"resolved": "1.84.0",
"contentHash": "4el2YP3cNJDVFPdzOso+LxGvdWP2rHxML4siq8VdonNypW2m4q503tHfCj6vK0L1UfxioE2hpFGb4ITEua73tg=="
},
+ "Microsoft.JavaScript.Hermes": {
+ "type": "Direct",
+ "requested": "[0.0.0-2512.22001-bc3d0ed7, )",
+ "resolved": "0.0.0-2512.22001-bc3d0ed7",
+ "contentHash": "aMuCKrIwkCAnT56+oKqmxgfIaAHlKRVt8IiG/jtMbG01QH1mLPwL7wP89jRMsYSJzikW96trqgpUllZZa3O+Qw=="
+ },
"Microsoft.Windows.CppWinRT": {
"type": "Direct",
"requested": "[2.0.230706.1, )",
@@ -25,11 +31,6 @@
"resolved": "1.1.1",
"contentHash": "AT3HlgTjsqHnWpBHSNeR0KxbLZD7bztlZVj7I8vgeYG9SYqbeFGh0TM/KVtC6fg53nrWHl3VfZFvb5BiQFcY6Q=="
},
- "Microsoft.JavaScript.Hermes": {
- "type": "Transitive",
- "resolved": "0.0.0-2512.22001-bc3d0ed7",
- "contentHash": "aMuCKrIwkCAnT56+oKqmxgfIaAHlKRVt8IiG/jtMbG01QH1mLPwL7wP89jRMsYSJzikW96trqgpUllZZa3O+Qw=="
- },
"Microsoft.SourceLink.Common": {
"type": "Transitive",
"resolved": "1.1.1",
diff --git a/vnext/Desktop/React.Windows.Desktop.vcxproj b/vnext/Desktop/React.Windows.Desktop.vcxproj
index 7b4d89f19b4..ab6c83d899d 100644
--- a/vnext/Desktop/React.Windows.Desktop.vcxproj
+++ b/vnext/Desktop/React.Windows.Desktop.vcxproj
@@ -270,7 +270,7 @@
-
+
diff --git a/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj b/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj
index 8d77f9b65d3..c44789aaba5 100644
--- a/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj
+++ b/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj
@@ -428,7 +428,7 @@
-
+
diff --git a/vnext/PropertySheets/External/Microsoft.ReactNative.Uwp.CSharpApp.targets b/vnext/PropertySheets/External/Microsoft.ReactNative.Uwp.CSharpApp.targets
index 1a340beb7e0..e0803acbbaf 100644
--- a/vnext/PropertySheets/External/Microsoft.ReactNative.Uwp.CSharpApp.targets
+++ b/vnext/PropertySheets/External/Microsoft.ReactNative.Uwp.CSharpApp.targets
@@ -25,7 +25,7 @@
-
+
-
+
diff --git a/vnext/PropertySheets/JSEngine.props b/vnext/PropertySheets/JSEngine.props
index 7f1754cf43d..f31aa12b4de 100644
--- a/vnext/PropertySheets/JSEngine.props
+++ b/vnext/PropertySheets/JSEngine.props
@@ -7,8 +7,9 @@
true
0.0.0-2512.22001-bc3d0ed7
+ Microsoft.JavaScript.Hermes
$(PkgMicrosoft_JavaScript_Hermes)
- $(NuGetPackageRoot)\Microsoft.JavaScript.Hermes\$(HermesVersion)
+ $(NuGetPackageRoot)\$(HermesPackageName)\$(HermesVersion)
false
true
diff --git a/vnext/Scripts/Tfs/Invoke-WebRequestWithRetry.ps1 b/vnext/Scripts/Tfs/Invoke-WebRequestWithRetry.ps1
new file mode 100644
index 00000000000..4858238050d
--- /dev/null
+++ b/vnext/Scripts/Tfs/Invoke-WebRequestWithRetry.ps1
@@ -0,0 +1,40 @@
+# Copyright (c) Microsoft Corporation.
+# Licensed under the MIT License.
+
+<#
+.SYNOPSIS
+ Downloads a file from a URI with retry logic.
+
+.PARAMETER Uri
+ The URI to download from.
+
+.PARAMETER OutFile
+ The output file path.
+
+.PARAMETER MaxRetries
+ Maximum number of download attempts. Default is 3.
+#>
+param(
+ [Parameter(Mandatory)]
+ [string]$Uri,
+
+ [Parameter(Mandatory)]
+ [string]$OutFile,
+
+ [int]$MaxRetries = 3
+)
+
+Set-StrictMode -Version Latest
+$ErrorActionPreference = 'Stop'
+
+for ($i = 1; $i -le $MaxRetries; $i++) {
+ try {
+ Write-Host "Downloading $OutFile (attempt $i of $MaxRetries)"
+ Invoke-WebRequest -Uri $Uri -OutFile $OutFile
+ return
+ } catch {
+ Write-Host "Attempt $i failed: $_"
+ if ($i -eq $MaxRetries) { throw }
+ Start-Sleep -Seconds (5 * $i)
+ }
+}
diff --git a/vnext/src-win/IntegrationTests/DummyTest.js b/vnext/src-win/IntegrationTests/DummyTest.js
index 20626c88e2d..fb5e60a8e59 100644
--- a/vnext/src-win/IntegrationTests/DummyTest.js
+++ b/vnext/src-win/IntegrationTests/DummyTest.js
@@ -6,32 +6,10 @@
'use strict';
-const React = require('react');
-const ReactNative = require('react-native');
+const {TurboModuleRegistry} = require('react-native');
+const TestModule = TurboModuleRegistry.get('TestModule');
-const {AppRegistry, StyleSheet, Text, View} = ReactNative;
-
-const {TestModule} = ReactNative.NativeModules;
-
-class DummyTest extends React.Component {
- componentDidMount() {
- TestModule.markTestPassed(true);
- }
-
- render() {
- return (
-
- Some text
-
- );
- }
+if (!TestModule) {
+ TestModule.markTestPassed(false, 'TestModule is not available');
}
-
-var styles = StyleSheet.create({
- container: {},
- row: {},
-});
-
-AppRegistry.registerComponent('DummyTest', () => DummyTest);
-
-module.exports = DummyTest;
+TestModule.markTestPassed(true);