Skip to content

Commit 56bff6a

Browse files
authored
Re-introduce Desktop integration tests (#16017) (#16023)
* Update packages locks * Update node locks * Add FollyWin32 lock * Add Prototype * Try adding IDLs from MSRN * Update Vars target * Add manifest, just in case * Export property bag symbols used by desk ITs * Grab missing generated includes * Instantiate msrn:ReactNativeHost * TODO: Obtain main queue * Implement TestUIDispatcher * Define HermesPackageName MSBuild property * split instance settins instantiation * Set up bundle source and platform * Init apartment at class init * Declare TestReactNativeHostHolder * Update lock * Add WinAppSDK dependency * Bootstrap WinApp runtime * Implement holder synchronization and UI queue * Update TestUIDispatcher to user DispatcherQueue * Update yarn lock * CallJSFunction: runApplication * CallJSFunction: unmountApplicationComponentAtRootTag * Add TestModule.h * Fix REACT_METHOD declarations * Implement sendAppEvent * Implement awaiting logic for TestModule * Add plumbing to make Dummy test pass * Add AppState mock * Place test support types into own compilation units and headers * Place test support types into own compilation units and headers * Rename MockCompositionContext -> TestCompositionContext * Set namespace * Rename Prototype.cpp to RNTesterHeadlessTests.cpp * Minor edit * Remove unused activation code The test DLL is loaded by testhost.exe, which knows nothing about the DLL's WinRT classes. The DLL has an embedded manifest (resource ID 2) that registers activatable WinRT classes (like ReactNativeHost). The code called CreateActCtxW to load that manifest and ActivateActCtx to push it onto the thread's activation context stack — so that RoGetActivationFactory could resolve those WinRT types at runtime. * Use infinite wait for events. Time limits will be enforceb by CI tasks. * Add failing condition to DummyTest * Add class diagram * Change files * Remove PR.md * Remove manifest * Remove comment * Implement WinRTActivationShims Leverages the Desktop DLL activation factories removing the need to declare some types in the DLL DEF list which are only required for testing and otherwise should stay module-private. * clang format * Remove unused test filter entries * Rename update CI references to RNTesterHeadlessTests * Put Windows.h in separate "paragraph" * Install Windows App SDK Runtime into build agents * Move checkout step before installers downloads
1 parent 298c57d commit 56bff6a

31 files changed

Lines changed: 1023 additions & 74 deletions

.ado/build-template.yml

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -265,31 +265,20 @@ extends:
265265
timeoutInMinutes: 360 # CodeQL requires 3x usual build timeout
266266
variables:
267267
- template: .ado/variables/windows.yml@self
268-
# Enable if any issues RNTesterIntegrationTests::* become unstable.
268+
# Enable if any issues RNTesterHeadlessTests::* become unstable.
269269
- name: Desktop.IntegrationTests.SkipRNTester
270270
value: false
271-
#5059 - Disable failing or intermittent tests (IntegrationTestHarness,WebSocket,Logging).
272271
#10732 - WebSocketIntegrationTest::SendReceiveSsl fails on Windows Server 2022.
273272
#12714 - Disable for first deployment of test website.
274-
#14217 - Reneable RNTesterIntegrationTests
275273
- name: Desktop.IntegrationTests.Filter
276274
value: >
277-
(FullyQualifiedName!=RNTesterIntegrationTests::IntegrationTestHarness)&
278-
(FullyQualifiedName!=RNTesterIntegrationTests::WebSocket)&
279-
(FullyQualifiedName!=RNTesterIntegrationTests::WebSocketBlob)&
280-
(FullyQualifiedName!=RNTesterIntegrationTests::WebSocketMultipleSend)&
281275
(FullyQualifiedName!=Microsoft::React::Test::WebSocketIntegrationTest::ConnectClose)&
282276
(FullyQualifiedName!=Microsoft::React::Test::WebSocketIntegrationTest::ConnectNoClose)&
283277
(FullyQualifiedName!=Microsoft::React::Test::WebSocketIntegrationTest::SendReceiveClose)&
284278
(FullyQualifiedName!=Microsoft::React::Test::WebSocketIntegrationTest::SendConsecutive)&
285279
(FullyQualifiedName!=Microsoft::React::Test::WebSocketIntegrationTest::SendReceiveLargeMessage)&
286280
(FullyQualifiedName!=Microsoft::React::Test::WebSocketIntegrationTest::SendReceiveSsl)&
287-
(FullyQualifiedName!=Microsoft::React::Test::HttpOriginPolicyIntegrationTest)&
288-
(FullyQualifiedName!=RNTesterIntegrationTests::Dummy)&
289-
(FullyQualifiedName!=RNTesterIntegrationTests::Fetch)&
290-
(FullyQualifiedName!=RNTesterIntegrationTests::XHRSample)&
291-
(FullyQualifiedName!=RNTesterIntegrationTests::Blob)&
292-
(FullyQualifiedName!=RNTesterIntegrationTests::Logging)
281+
(FullyQualifiedName!=Microsoft::React::Test::HttpOriginPolicyIntegrationTest)
293282
#6799 - HostFunctionTest, HostObjectProtoTest crash under JSI/V8;
294283
# PreparedJavaScriptSourceTest asserts/fails under JSI/ChakraCore
295284
- name: Desktop.UnitTests.Filter

.ado/jobs/desktop-single.yml

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21,35 +21,25 @@ parameters:
2121
- Continuous
2222

2323
steps:
24+
- template: ../templates/checkout-shallow.yml
25+
2426
# Set up IIS for integration tests
2527
- pwsh: |
2628
Install-WindowsFeature -Name Web-Server, Web-Scripting-Tools
2729
displayName: Install IIS
2830
2931
- pwsh: |
30-
function Invoke-WebRequestWithRetry($Uri, $OutFile, $MaxRetries = 3) {
31-
for ($i = 1; $i -le $MaxRetries; $i++) {
32-
try {
33-
Write-Host "Downloading $OutFile (attempt $i of $MaxRetries)"
34-
Invoke-WebRequest -Uri $Uri -OutFile $OutFile
35-
return
36-
} catch {
37-
Write-Host "Attempt $i failed: $_"
38-
if ($i -eq $MaxRetries) { throw }
39-
Start-Sleep -Seconds (5 * $i)
40-
}
41-
}
42-
}
32+
$DownloadScript = "$(Build.SourcesDirectory)\vnext\Scripts\Tfs\Invoke-WebRequestWithRetry.ps1"
4333
44-
Invoke-WebRequestWithRetry `
34+
& $DownloadScript `
4535
-Uri 'https://download.visualstudio.microsoft.com/download/pr/20598243-c38f-4538-b2aa-af33bc232f80/ea9b2ca232f59a6fdc84b7a31da88464/dotnet-hosting-8.0.3-win.exe' `
4636
-OutFile dotnet-hosting-8.0.3-win.exe
4737
4838
Write-Host 'Installing .NET hosting bundle'
4939
Start-Process -Wait -FilePath .\dotnet-hosting-8.0.3-win.exe -ArgumentList '/INSTALL', '/QUIET', '/NORESTART'
5040
Write-Host 'Installed .NET hosting bundle'
5141
52-
Invoke-WebRequestWithRetry `
42+
& $DownloadScript `
5343
-Uri 'https://download.visualstudio.microsoft.com/download/pr/f2ec926e-0d98-4a8b-8c70-722ccc2ca0e5/b59941b0c60f16421679baafdb7e9338/dotnet-sdk-7.0.407-win-x64.exe' `
5444
-OutFile dotnet-sdk-7.0.407-win-x64.exe
5545
@@ -58,7 +48,17 @@ steps:
5848
Write-Host 'Installed .NET 7 SDK'
5949
displayName: Install the .NET Core Hosting Bundle
6050
61-
- template: ../templates/checkout-shallow.yml
51+
- pwsh: |
52+
$DownloadScript = "$(Build.SourcesDirectory)\vnext\Scripts\Tfs\Invoke-WebRequestWithRetry.ps1"
53+
54+
& $DownloadScript `
55+
-Uri 'https://aka.ms/windowsappsdk/1.8/latest/windowsappruntimeinstall-x64.exe' `
56+
-OutFile windowsappruntimeinstall-x64.exe
57+
58+
Write-Host 'Installing Windows App SDK Runtime'
59+
Start-Process -Wait -FilePath .\windowsappruntimeinstall-x64.exe -ArgumentList '--quiet'
60+
Write-Host 'Installed Windows App SDK Runtime'
61+
displayName: Install Windows App SDK Runtime
6262
6363
- template: ../templates/prepare-js-env.yml
6464

@@ -72,7 +72,7 @@ steps:
7272

7373
- ${{ if eq(variables['Desktop.IntegrationTests.SkipRNTester'], true) }}:
7474
- pwsh: |
75-
$newValue = '(FullyQualifiedName!~RNTesterIntegrationTests::)&' + "$(Desktop.IntegrationTests.Filter)"
75+
$newValue = '(FullyQualifiedName!~Microsoft::React::Test::RNTesterHeadlessTests::)&' + "$(Desktop.IntegrationTests.Filter)"
7676
Write-Host "##vso[task.setvariable variable=Desktop.IntegrationTests.Filter]$newValue"
7777
displayName: Update Desktop.IntegrationTests.Filter to exclude RNTester integration tests
7878

Directory.Build.targets

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@
107107
ReactNativeWindowsDir;
108108
RnwNewArch;
109109
FollyDir;
110+
IncludeFabricInterface;
111+
UseFabric;
110112
YogaDir;
111113
WinVer;
112114
" />
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "prerelease",
3+
"comment": "Re-introduce Desktop integration tests",
4+
"packageName": "react-native-windows",
5+
"email": "julio.rocha@microsoft.com",
6+
"dependentChangeType": "patch"
7+
}

vnext/Desktop.DLL/React.Windows.Desktop.DLL.vcxproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@
179179
</ItemGroup>
180180
<ItemGroup>
181181
<PackageReference Include="boost" Version="1.84.0.0" />
182-
<PackageReference Include="Microsoft.JavaScript.Hermes" Version="$(HermesVersion)" />
182+
<PackageReference Include="$(HermesPackageName)" Version="$(HermesVersion)" />
183183
<PackageReference Include="$(V8PackageName)" Version="$(V8Version)" Condition="'$(UseV8)' == 'true'" />
184184
</ItemGroup>
185185
<Choose>
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
#include "TestAppState.h"
5+
6+
namespace Microsoft::React::Test {
7+
8+
void AppState::Initialize(winrt::Microsoft::ReactNative::ReactContext const &) noexcept {}
9+
10+
void AppState::GetCurrentAppState(
11+
std::function<void(::Microsoft::ReactNativeSpecs::AppStateSpec_AppState const &)> const &success,
12+
std::function<void(winrt::Microsoft::ReactNative::JSValue const &)> const &) noexcept {
13+
success({.app_state = "active"});
14+
}
15+
16+
void AppState::AddListener(std::string) noexcept {}
17+
18+
void AppState::RemoveListeners(double) noexcept {}
19+
20+
::Microsoft::ReactNativeSpecs::AppStateSpec_AppStateConstants AppState::GetConstants() noexcept {
21+
return {.initialAppState = "active"};
22+
}
23+
24+
} // namespace Microsoft::React::Test
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
#pragma once
5+
6+
#include <codegen/NativeAppStateSpec.g.h>
7+
#include <NativeModules.h>
8+
9+
namespace Microsoft::React::Test {
10+
11+
REACT_MODULE(AppState)
12+
struct AppState {
13+
using ModuleSpec = ::Microsoft::ReactNativeSpecs::AppStateSpec;
14+
15+
REACT_INIT(Initialize)
16+
void Initialize(winrt::Microsoft::ReactNative::ReactContext const &) noexcept;
17+
18+
REACT_METHOD(GetCurrentAppState, L"getCurrentAppState")
19+
void GetCurrentAppState(
20+
std::function<void(::Microsoft::ReactNativeSpecs::AppStateSpec_AppState const &)> const &success,
21+
std::function<void(winrt::Microsoft::ReactNative::JSValue const &)> const &) noexcept;
22+
23+
REACT_METHOD(AddListener, L"addListener")
24+
void AddListener(std::string) noexcept;
25+
26+
REACT_METHOD(RemoveListeners, L"removeListeners")
27+
void RemoveListeners(double) noexcept;
28+
29+
REACT_GET_CONSTANTS(GetConstants)
30+
::Microsoft::ReactNativeSpecs::AppStateSpec_AppStateConstants GetConstants() noexcept;
31+
};
32+
33+
} // namespace Microsoft::React::Test
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
#include "TestDeviceInfo.h"
5+
6+
namespace Microsoft::React::Test {
7+
8+
void DeviceInfo::Initialize(winrt::Microsoft::ReactNative::ReactContext const &) noexcept {}
9+
10+
::Microsoft::ReactNativeSpecs::DeviceInfoSpec_DeviceInfoConstants DeviceInfo::GetConstants() noexcept {
11+
::Microsoft::ReactNativeSpecs::DeviceInfoSpec_DeviceInfoConstants constants;
12+
::Microsoft::ReactNativeSpecs::DeviceInfoSpec_DisplayMetrics dm;
13+
dm.fontScale = 1;
14+
dm.height = 1024;
15+
dm.width = 1024;
16+
dm.scale = 1;
17+
constants.Dimensions.screen = dm;
18+
constants.Dimensions.window = dm;
19+
return constants;
20+
}
21+
22+
} // namespace Microsoft::React::Test
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
#pragma once
5+
6+
#include <codegen/NativeDeviceInfoSpec.g.h>
7+
#include <NativeModules.h>
8+
9+
namespace Microsoft::React::Test {
10+
11+
REACT_MODULE(DeviceInfo)
12+
struct DeviceInfo {
13+
using ModuleSpec = ::Microsoft::ReactNativeSpecs::DeviceInfoSpec;
14+
15+
REACT_INIT(Initialize)
16+
void Initialize(winrt::Microsoft::ReactNative::ReactContext const &) noexcept;
17+
18+
REACT_GET_CONSTANTS(GetConstants)
19+
::Microsoft::ReactNativeSpecs::DeviceInfoSpec_DeviceInfoConstants GetConstants() noexcept;
20+
};
21+
22+
} // namespace Microsoft::React::Test
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
#pragma once
5+
6+
#include <windows.h>
7+
8+
#include <NativeModules.h>
9+
10+
// Standard Library
11+
#include <atomic>
12+
#include <functional>
13+
#include <string>
14+
15+
namespace Microsoft::React::Test {
16+
17+
enum class TestStatus { Pending = 0, Passed, Failed };
18+
19+
REACT_MODULE(TestModule)
20+
struct TestModule {
21+
// Static test signaling - call Reset() before each test.
22+
static void Reset() noexcept {
23+
ResetEvent(s_completed.get());
24+
s_status = TestStatus::Pending;
25+
}
26+
27+
static TestStatus AwaitCompletion(DWORD timeoutMs = INFINITE) noexcept {
28+
WaitForSingleObject(s_completed.get(), timeoutMs);
29+
return s_status;
30+
}
31+
32+
REACT_INIT(Initialize)
33+
void Initialize(winrt::Microsoft::ReactNative::ReactContext const &reactContext) noexcept {
34+
m_reactContext = reactContext;
35+
}
36+
37+
REACT_METHOD(MarkTestCompleted, L"markTestCompleted")
38+
void MarkTestCompleted() noexcept {
39+
MarkTestPassed(true);
40+
}
41+
42+
REACT_METHOD(MarkTestPassed, L"markTestPassed")
43+
void MarkTestPassed(bool success) noexcept {
44+
s_status = success ? TestStatus::Passed : TestStatus::Failed;
45+
SetEvent(s_completed.get());
46+
}
47+
48+
REACT_METHOD(VerifySnapshot, L"verifySnapshot")
49+
void VerifySnapshot(std::function<void(bool)> const &callback) noexcept {
50+
// Snapshot testing is not supported on Windows; always report success.
51+
callback(true);
52+
}
53+
54+
REACT_METHOD(SendAppEvent, L"sendAppEvent")
55+
void SendAppEvent(std::string name, ::React::JSValue body) noexcept {
56+
m_reactContext.EmitJSEvent(L"RCTDeviceEventEmitter", winrt::to_hstring(name), body);
57+
}
58+
59+
REACT_METHOD(ShouldResolve, L"shouldResolve")
60+
void ShouldResolve(::React::ReactPromise<int> &&result) noexcept {
61+
result.Resolve(1);
62+
}
63+
64+
REACT_METHOD(ShouldReject, L"shouldReject")
65+
void ShouldReject(::React::ReactPromise<::React::JSValue> &&result) noexcept {
66+
result.Reject(::React::ReactError{});
67+
}
68+
69+
TestStatus Status() const noexcept {
70+
return s_status;
71+
}
72+
73+
private:
74+
winrt::Microsoft::ReactNative::ReactContext m_reactContext;
75+
76+
static inline std::atomic<TestStatus> s_status{TestStatus::Pending};
77+
static inline winrt::handle s_completed{CreateEvent(nullptr, TRUE /*manualReset*/, FALSE /*initialState*/, nullptr)};
78+
};
79+
80+
} // namespace Microsoft::React::Test

0 commit comments

Comments
 (0)