Enable integration test web application (#12714)

* Create TestServices project
This commit is contained in:
Julio César Rocha 2024-03-20 15:42:33 -07:00 коммит произвёл GitHub
Родитель 86bf444670
Коммит a09af289ff
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
30 изменённых файлов: 725 добавлений и 204 удалений

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

@ -60,7 +60,7 @@ parameters:
- X86ReleaseFabric:
BuildConfiguration: Release
BuildPlatform: x86
UseFabric: true
UseFabric: true
jobs:
- ${{ each config in parameters.buildMatrix }}:
@ -78,11 +78,14 @@ jobs:
#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.
# RNTesterIntegrationTests::WebSocket
# RNTesterIntegrationTests::WebSocketBlob
- name: Desktop.IntegrationTests.Filter
value: >
(FullyQualifiedName!=RNTesterIntegrationTests::Blob)&
(FullyQualifiedName!=RNTesterIntegrationTests::IntegrationTestHarness)&
(FullyQualifiedName!=WebSocketResourcePerformanceTest::ProcessThreadsPerResource)&
(FullyQualifiedName!=RNTesterIntegrationTests::WebSocket)&
(FullyQualifiedName!=RNTesterIntegrationTests::WebSocketBlob)&
(FullyQualifiedName!=WebSocketIntegrationTest::SendReceiveSsl)&
(FullyQualifiedName!=Microsoft::React::Test::HttpOriginPolicyIntegrationTest)
#6799 -
@ -100,6 +103,31 @@ jobs:
cancelTimeoutInMinutes: 5 # how much time to give 'run always even if cancelled tasks' before killing them
steps:
# Set up IIS tests {
- pwsh: |
Install-WindowsFeature -Name Web-Server, Web-Scripting-Tools
displayName: Install IIS
- pwsh: |
Invoke-WebRequest `
-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
Write-Host 'Installing .NET hosting bundle'
Start-Process -Wait -FilePath .\dotnet-hosting-8.0.3-win.exe -ArgumentList '/INSTALL', '/QUIET', '/NORESTART'
Write-Host 'Installed .NET hosting bundle'
Invoke-WebRequest `
-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
Write-Host 'Installing .NET 7 SDK'
Start-Process -Wait -FilePath .\dotnet-sdk-7.0.407-win-x64.exe -ArgumentList '/INSTALL', '/QUIET', '/NORESTART'
Write-Host 'Installed .NET 7 SDK'
displayName: Install the .NET Core Hosting Bundle
# } Set up IIS tests
- template: ../templates/checkout-shallow.yml
- template: ../templates/prepare-js-env.yml
@ -168,11 +196,89 @@ jobs:
filePath: $(Build.SourcesDirectory)\vnext\Scripts\Tfs\Start-TestServers.ps1
arguments: -SourcesDirectory $(Build.SourcesDirectory)\vnext -Preload -SleepSeconds 120
- task: DotNetCoreCLI@2
displayName: Publish Test Website
inputs:
command: publish
publishWebProjects: false
zipAfterPublish: false
projects: $(Build.SourcesDirectory)\vnext\TestWebsite\Microsoft.ReactNative.Test.Website.csproj
arguments: --configuration ${{ matrix.BuildConfiguration }}
- pwsh: |
# Create and make available to IIS
$cert = New-SelfSignedCertificate `
-Type SSLServerAuthentication `
-KeyExportPolicy Exportable `
-Subject 'CN=localhost' `
-NotAfter ([DateTime]::Now).AddHours(2) `
-CertStoreLocation Cert:\LocalMachine\My\
$certPath = "${env:TEMP}\localhost.pfx"
$certPass = -join ('a'..'z' | Get-Random -Count 32) | ConvertTo-SecureString -AsPlainText -Force
$certHash = $cert.Thumbprint
Write-Host "##vso[task.setvariable variable=TestWebsiteCertificateThumbprint]$certHash"
# Export PFX
$cert | Export-PfxCertificate -FilePath $certPath -Password $certPass
# Trust globally
Import-PfxCertificate `
-Exportable `
-FilePath $certPath `
-Password $certPass `
-CertStoreLocation Cert:\LocalMachine\Root\
displayName: Install SSL Certificate
- task: IISWebAppManagementOnMachineGroup@0
displayName: Create Test Website
inputs:
EnableIIS: false
IISDeploymentType: IISWebsite
ActionIISWebsite: CreateOrUpdateWebsite
SSLCertThumbPrint: $(TestWebsiteCertificateThumbprint)
# IIS Website
WebsiteName: RNW Test Website
WebsitePhysicalPath: $(Build.SourcesDirectory)\vnext\target\${{ matrix.BuildPlatform }}\${{ matrix.BuildConfiguration }}\Microsoft.ReactNative.Test.Website\Publish
WebsitePhysicalPathAuth: WebsiteUserPassThrough
CreateOrUpdateAppPoolForWebsite: false
ConfigureAuthenticationForWebsite: false
# IIS Application pool
AppPoolNameForWebsite: DefaultAppPool
# IIS Bindings
# See https://stackoverflow.com/questions/60089756
AddBinding: true
Bindings: |
{
bindings: [
{
"protocol": "http",
"ipAddress": "*",
"port": "5555",
"sslThumbprint": "",
"sniFlag": false
},
{
"protocol": "https",
"ipAddress": "*",
"port": "5543",
"sslThumbprint": "$(TestWebsiteCertificateThumbprint)",
"sniFlag": false
}
]
}
- task: PowerShell@2
displayName: Check the metro bundle server
displayName: Ensure servers readiness
inputs:
targetType: 'inline'
script: Invoke-WebRequest -UseBasicParsing -Uri "http://localhost:8081/IntegrationTests/IntegrationTestsApp.bundle?platform=windows&dev=true"
script: |
# Test website
Invoke-WebRequest -Uri 'http://localhost:5555'
Invoke-WebRequest -Uri 'https://localhost:5543'
# Bundler
Invoke-WebRequest -UseBasicParsing -Uri "http://localhost:8081/IntegrationTests/IntegrationTestsApp.bundle?platform=windows&dev=true"
- task: VSTest@2
displayName: Run Desktop Integration Tests

1
.gitignore поставляемый
Просмотреть файл

@ -140,6 +140,7 @@ package-lock.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
vnext/.vscode/*
#JavaScript files
*.jsbundle

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

@ -35,7 +35,7 @@
>
<Output TaskParameter="ExitCode" ItemName="_ReactNativeYarnExitCode"/>
</Exec>
<Message Text="yarn install: Succeeded" Condition="'%(_ReactNativeYarnExitCode.Identity)' == '0'" Importance="High" />
<Message Text="yarn install: Failed" Condition="'%(_ReactNativeYarnExitCode.Identity)' != '0'" Importance="High" />
@ -91,8 +91,10 @@
VCTargetsPath;
UserRootDir;
ProjectHome;
BaseIntermediateOutputPath;
IntermediateOutputPath;
OutputPath;
OS;
" />
<_VarsCustom Include="
RootDir;

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

@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "Implement test website",
"packageName": "react-native-windows",
"email": "julio.rocha@microsoft.com",
"dependentChangeType": "patch"
}

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

@ -743,6 +743,46 @@ TEST_CLASS(HttpOriginPolicyIntegrationTest)
TestOriginPolicy(serverArgs, clientArgs, s_shouldFail);
} // FullCors304ForSimpleGetFails
TEST_METHOD(OfficeDev_OfficeJS_4144)
{
SetRuntimeOptionString("Http.GlobalOrigin", "http://orig.in");
SetRuntimeOptionInt("Http.OriginPolicy", static_cast<int32_t>(OriginPolicy::CrossOriginResourceSharing));
ClientParams clientArgs(http::verb::get, {} /*headers*/);
auto resource = IHttpResource::Make();
resource->SetOnResponse([&clientArgs](int64_t, IHttpResource::Response&& res)
{
clientArgs.Response = std::move(res);
});
resource->SetOnData([&clientArgs](int64_t, string&& content)
{
clientArgs.ResponseContent = std::move(content);
clientArgs.ContentPromise.set_value();
});
resource->SetOnError([&clientArgs](int64_t, string&& message, bool)
{
clientArgs.ErrorMessage = std::move(message);
clientArgs.ContentPromise.set_value();
});
resource->SendRequest(
string { http::to_string(clientArgs.Method).data() },
string { "http://localhost:5555/officedev/office-js/issues/4144"},
0, /*requestId*/
std::move(clientArgs.RequestHeaders),
{ { "string", "" } }, /*data*/
"text",
false, /*useIncrementalUpdates*/
0, /*timeout*/
clientArgs.WithCredentials, /*withCredentials*/
[](int64_t) {} /*reactCallback*/
);
clientArgs.ContentPromise.get_future().wait();
Assert::AreEqual({}, clientArgs.ErrorMessage);
}
TEST_METHOD(FullCorsPreflightSucceeds)
{
ServerParams serverArgs(s_port);

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

@ -209,7 +209,6 @@ TEST_CLASS (RNTesterIntegrationTests) {
}
BEGIN_TEST_METHOD_ATTRIBUTE(WebSocketBlob)
TEST_IGNORE()
END_TEST_METHOD_ATTRIBUTE()
TEST_METHOD(WebSocketBlob) {
auto result = m_runner.RunTest("IntegrationTests/WebSocketBlobTest", "WebSocketBlobTest");

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

@ -280,7 +280,44 @@ TEST_CLASS (WebSocketIntegrationTest)
END_TEST_METHOD_ATTRIBUTE()
TEST_METHOD(SendReceiveSsl)
{
SendReceiveCloseBase(/*isSecure*/ true);
auto ws = IWebSocketResource::Make();
promise<size_t> sentSizePromise;
ws->SetOnSend([&sentSizePromise](size_t size)
{
sentSizePromise.set_value(size);
});
promise<string> receivedPromise;
ws->SetOnMessage([&receivedPromise](size_t size, const string& message, bool isBinary)
{
receivedPromise.set_value(message);
});
string clientError{};
ws->SetOnError([&clientError, &sentSizePromise, &receivedPromise](Error err)
{
clientError = err.Message;
sentSizePromise.set_value(0);
receivedPromise.set_value("");
});
string sent = "prefix";
auto expectedSize = sent.size();
ws->Connect("wss://localhost:5543/rnw/websockets/echosuffix");
ws->Send(std::move(sent));
// Block until response is received. Fail in case of a remote endpoint failure.
auto sentSizeFuture = sentSizePromise.get_future();
sentSizeFuture.wait();
auto sentSize = sentSizeFuture.get();
auto receivedFuture = receivedPromise.get_future();
receivedFuture.wait();
string received = receivedFuture.get();
Assert::AreEqual({}, clientError);
ws->Close(CloseCode::Normal, "Closing after reading");
Assert::AreEqual({}, clientError);
Assert::AreEqual(expectedSize, sentSize);
Assert::AreEqual({"prefix_response"}, received);
}
BEGIN_TEST_METHOD_ATTRIBUTE(SendBinary)

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

@ -59,6 +59,9 @@ TEST_CLASS (WebSocketResourcePerformanceTest) {
/// several times, then measure the amount of allocated threads. Important. This
/// test must be run in isolation (no other tests running concurrently).
///
BEGIN_TEST_METHOD_ATTRIBUTE(ProcessThreadsPerResource)
TEST_IGNORE()
END_TEST_METHOD_ATTRIBUTE()
TEST_METHOD(ProcessThreadsPerResource) {
// About 3 seconds total running time.
// 6, if we increase this value to 100.
@ -71,11 +74,6 @@ TEST_CLASS (WebSocketResourcePerformanceTest) {
bool errorFound = false;
string errorMessage;
auto server = std::make_shared<Test::WebSocketServer>(s_port);
server->SetMessageFactory([](string &&message) { return message + "_response"; });
// TODO: #4493 - Allow TestWebSocketServer to handle multiple incoming messages.
// server->Start();
// WebSocket resources scope.
{
vector<shared_ptr<IWebSocketResource>> resources;
@ -112,7 +110,7 @@ TEST_CLASS (WebSocketResourcePerformanceTest) {
errorFound = true;
errorMessage = error.Message;
});
ws->Connect("ws://localhost:" + std::to_string(s_port));
ws->Connect("ws://localhost:5555");
resources.push_back(std::move(ws));
} // Create and store WS resources.
@ -127,8 +125,6 @@ TEST_CLASS (WebSocketResourcePerformanceTest) {
ws->Close();
}
}
// TODO: #4493 - Allow TestWebSocketServer to handle multiple incoming messages.
// server->Stop();
int32_t finalThreadCount = threadCount.load();
int64_t threadsPerResource = (finalThreadCount - startThreadCount) / resourceTotal;

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

@ -30,7 +30,7 @@
[MSBuild]::NormalizeDirectory on relative paths since cwd is not always correct. This logic should prefer to operate
on full paths and avoid extra normalization.
-->
<PropertyGroup>
<PropertyGroup Label="NodeNativeDeps" Condition="'$(IgnoreNodeNativeDeps)' != 'true'">
<ReactNativeWindowsDir Condition="'$(ReactNativeWindowsDir)' == ''">$(MSBuildThisFileDirectory)</ReactNativeWindowsDir>
<ReactNativeDir Condition="'$(ReactNativeDir)' == ''">$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), 'node_modules\react-native\package.json'))\node_modules\react-native\</ReactNativeDir>
@ -80,4 +80,4 @@
<RestoreUseStaticGraphEvaluation Condition="'$(BuildingInsideVisualStudio)' == 'true' AND $([MSBuild]::VersionLessThan('$(MSBuildVersion)', '17.6')) AND '$(DisableRestoreUseStaticGraphEvaluation)' != 'true'">true</RestoreUseStaticGraphEvaluation>
</PropertyGroup>
</Project>
</Project>

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

@ -105,6 +105,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.ReactNative.Cxx",
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ReactCommon.UnitTests", "ReactCommon.UnitTests\ReactCommon.UnitTests.vcxproj", "{B0941079-7441-4A69-868C-FE5EC62C2E9E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.ReactNative.Test.Website", "TestWebsite\Microsoft.ReactNative.Test.Website.csproj", "{C5B2EB41-849E-41F7-BC70-DEFF26F09E5E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
@ -285,6 +287,18 @@ Global
{B0941079-7441-4A69-868C-FE5EC62C2E9E}.Release|x64.ActiveCfg = Release|x64
{B0941079-7441-4A69-868C-FE5EC62C2E9E}.Release|x64.Build.0 = Release|x64
{B0941079-7441-4A69-868C-FE5EC62C2E9E}.Release|x86.ActiveCfg = Release|x64
{C5B2EB41-849E-41F7-BC70-DEFF26F09E5E}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{C5B2EB41-849E-41F7-BC70-DEFF26F09E5E}.Debug|ARM64.Build.0 = Debug|Any CPU
{C5B2EB41-849E-41F7-BC70-DEFF26F09E5E}.Debug|x64.ActiveCfg = Debug|Any CPU
{C5B2EB41-849E-41F7-BC70-DEFF26F09E5E}.Debug|x64.Build.0 = Debug|Any CPU
{C5B2EB41-849E-41F7-BC70-DEFF26F09E5E}.Debug|x86.ActiveCfg = Debug|Any CPU
{C5B2EB41-849E-41F7-BC70-DEFF26F09E5E}.Debug|x86.Build.0 = Debug|Any CPU
{C5B2EB41-849E-41F7-BC70-DEFF26F09E5E}.Release|ARM64.ActiveCfg = Release|Any CPU
{C5B2EB41-849E-41F7-BC70-DEFF26F09E5E}.Release|ARM64.Build.0 = Release|Any CPU
{C5B2EB41-849E-41F7-BC70-DEFF26F09E5E}.Release|x64.ActiveCfg = Release|Any CPU
{C5B2EB41-849E-41F7-BC70-DEFF26F09E5E}.Release|x64.Build.0 = Release|Any CPU
{C5B2EB41-849E-41F7-BC70-DEFF26F09E5E}.Release|x86.ActiveCfg = Release|Any CPU
{C5B2EB41-849E-41F7-BC70-DEFF26F09E5E}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

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

@ -30,16 +30,15 @@ param (
[switch] $NoRun,
[switch] $UseNodeWsServer,
[switch] $List,
[System.IO.FileInfo] $VsTest = "${env:ProgramFiles}\Microsoft Visual Studio\2022\Enterprise\" +
"Common7\IDE\CommonExtensions\Microsoft\TestWindow\vstest.console.exe",
[System.IO.FileInfo] $VsTest =
"$(& "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" -latest -property installationPath)\" +
"Common7\IDE\CommonExtensions\Microsoft\TestWindow\vstest.console.exe",
[System.IO.DirectoryInfo] $ReactNativeLocation = "$($PSScriptRoot | Split-Path)",
[System.IO.FileInfo] $NodePath = (Get-Command node.exe).Definition,
[System.IO.FileInfo] $DotNetPath = (Get-Command dotnet.exe).Definition,
[System.IO.FileInfo] $NpmPath = (Get-Command npm.cmd).Definition
)
@ -59,9 +58,7 @@ if ($List) {
# Ensure test services are online.
if (! $NoServers) {
$packager = Find-Packager
if ($UseNodeWsServer.IsPresent) {
$wsServer = Find-WebSocketServer
}
$webSite = Find-TestWebsiteServer
$notFound = $false
if (!$packager) {
@ -72,17 +69,26 @@ if (! $NoServers) {
Write-Host 'Found Packager.'
}
if (!$wsServer -and $UseNodeWsServer.IsPresent) {
Write-Warning 'WebSocket server not found. Attempting to start...'
Start-WebSocketServer -ReactNativeLocation $ReactNativeLocation -NodePath $NodePath
if (!$webSite) {
Start-Process `
-FilePath $DotNetPath `
-PassThru `
-ArgumentList `
run,
--project,
$ReactNativeLocation\TestWebSite\Microsoft.ReactNative.Test.Website.csproj
$notFound = $true
} elseif ($UseNodeWsServer.IsPresent) {
Write-Host 'Found WebSocket server.'
} else {
Write-Host 'Found Test Website Server'
}
if ($Preload -and $notFound) {
Start-Sleep -Seconds $Delay
# Ensure test website responds to default HTTP GET request.
Invoke-WebRequest -Uri 'http://localhost:5555'
# Preload the RNTesterApp integration bundle for better performance in integration tests.
Invoke-WebRequest -UseBasicParsing -Uri "http://localhost:8081/IntegrationTests/IntegrationTestsApp.bundle?platform=windows&dev=true" | Out-Null
}
@ -92,8 +98,9 @@ if ($NoRun) {
Exit
}
$filter = ''
if ($Include.Count) {
$filter = "(FullyQualifiedName~" + ($Include -join ')&(FullyQualifiedName~') + ")"
$filter += "(FullyQualifiedName~" + ($Include -join ')&(FullyQualifiedName~') + ")"
}
if ($Exclude.Count) {
@ -101,4 +108,8 @@ if ($Exclude.Count) {
}
# Run Integration Test assemblies.
& $VsTest $Assemblies --InIsolation --Platform:$Platform ('', "--TestCaseFilter:$filter")[$filter.Length -gt 0]
if ($filter.Length -gt 0) {
& $VsTest $Assemblies --InIsolation --Platform:$Platform "--TestCaseFilter:$filter"
} else {
& $VsTest $Assemblies --InIsolation --Platform:$Platform
}

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

@ -61,24 +61,6 @@ function Start-Packager {
return Start-Npm -WorkingDirectory $ReactNativeLocation -NoNewWindow:$NoNewWindow -NpmPath $NpmPath
}
function Start-WebSocketServer {
param (
[Parameter(Mandatory=$true)]
[ValidateScript({Test-Path $_})]
[string] $ReactNativeLocation,
[switch] $NoNewWindow,
[Parameter(Mandatory=$true)]
[ValidateScript({Test-Path $_})]
[string] $NodePath
)
return Start-Node -ScriptPath $ReactNativeLocation\IntegrationTests\websocket_integration_test_server.js `
-NoNewWindow:$NoNewWindow `
-NodePath $NodePath
}
function Find-Packager {
try {
return Get-Process -Id (Get-NetTCPConnection -ErrorAction Ignore -LocalPort 8081).OwningProcess
@ -88,23 +70,15 @@ function Find-Packager {
}
}
function Find-WebSocketServer {
function Find-TestWebsiteServer {
try {
return Get-Process -Id (Get-NetTCPConnection -ErrorAction Ignore -LocalPort 5555).OwningProcess
return Get-Process -id (Get-NetTCPConnection -ErrorAction Ignore -LocalPort 5555).OwningProcess
}
catch {
return $null
}
}
function Stop-WebSocketServer {
$proc = Find-WebSocketServer
if ($proc) {
Stop-Process $proc
}
}
function Stop-Packager {
$proc = Find-Packager

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

@ -9,9 +9,7 @@ param (
[switch] $Preload,
[int] $SleepSeconds = 10,
[switch] $UseNodeWsServer
[int] $SleepSeconds = 10
)
Write-Host "Starting packager"
@ -26,17 +24,6 @@ Start-Process npm -PassThru `
Write-Host 'Started packager'
if ($UseNodeWsServer.IsPresent) {
Write-Host 'Starting WebSocket server'
Start-Process -PassThru `
-FilePath (Get-Command node.exe).Definition `
-ArgumentList "${SourcesDirectory}\IntegrationTests\websocket_integration_test_server.js" `
-OutVariable wsProc
Write-Host 'Started WebSocket server'
}
if ($Preload) {
Write-Host 'Preloading bundles'
@ -50,10 +37,3 @@ if ($Preload) {
# Use the environment variables input below to pass secret variables to this script.
Write-Host "##vso[task.setvariable variable=PackagerId;]$($packagerProc.Id)"
if ($UseNodeWsServer.IsPresent) {
Write-Host "##vso[task.setvariable variable=WebSocketServerId;]$($wsProc.Id)"
return ($packagerProc, $wsProc)
} else {
return ($packagerProc)
}

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

@ -4,14 +4,9 @@
# Stop-TestServers.ps1
#
param (
$WebSocketServerId = $env:WebSocketServerId,
$PackagerId = $env:PackagerId
)
Write-Host 'Stopping WebSocket server'
Stop-Process -Id $WebSocketServerId
Write-Host 'Stopped WebSocket server'
Write-Host 'Stopping packager'
Stop-Process -Id $PackagerId
Write-Host 'Stopped packager'

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

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<Project>
<PropertyGroup>
<IgnoreNodeNativeDeps>true</IgnoreNodeNativeDeps>
</PropertyGroup>
<!-- This import will noop when customer code is built. This import is here to help building the bits in the react-native-windows repository. -->
<Import Condition="Exists($([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../')))" Project="$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../'))" />
</Project>

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

@ -0,0 +1,108 @@
using System;
using System.Net.WebSockets;
using System.Text;
namespace Facebook.React.Test
{
public sealed class RNTesterIntegrationTests
{
static List<WebSocket> wsConnections = new List<WebSocket>();
public static async Task WebSocketTest(HttpContext context)
{
var announcement = @"
WebSocket integration test server
This will send each incoming message back, with the string '_response' appended.
An incoming message of 'exit' will shut down the server.
";
await Console.Out.WriteLineAsync(announcement);
using var ws = await context.WebSockets.AcceptWebSocketAsync();
wsConnections.Add(ws);
if (ws.State == WebSocketState.Open)
{
var connectMessage = "hello";
var bytes = Encoding.UTF8.GetBytes(connectMessage);
var segment = new ArraySegment<byte>(bytes);
await ws.SendAsync(segment, WebSocketMessageType.Text, true, CancellationToken.None);
}
while (true)
{
if (ws.State == WebSocketState.Open)
{
async Task<string> receiveMessage(WebSocket socket)
{
// Read incoming message
var inputBytes = new byte[1024];
WebSocketReceiveResult result;
int total = 0;
do
{
result = await socket.ReceiveAsync(new ArraySegment<byte>(inputBytes), CancellationToken.None);
total += result.Count;
} while (result != null && !result.EndOfMessage);
return Encoding.UTF8.GetString(inputBytes, 0, total);
};
var inputMessage = await receiveMessage(ws);
await Console.Out.WriteLineAsync($"Received message: {inputMessage}");
if (inputMessage == "exit")
{
await Console.Out.WriteLineAsync("WebSocket integration test server exit");
}
var outputMessage = $"{inputMessage}_response";
var outputBytes = Encoding.UTF8.GetBytes(outputMessage);
await ws.SendAsync(outputBytes, WebSocketMessageType.Text, true, CancellationToken.None);
}
else if (ws.State == WebSocketState.Closed || ws.State == WebSocketState.Aborted)
{
break;
}
}
}
public static async Task WebSocketBinaryTest(HttpContext context)
{
var ws = await context.WebSockets.AcceptWebSocketAsync();
wsConnections.Add(ws);
while (true)
{
if (ws.State == WebSocketState.Open)
{
async Task<string> receiveMessage(WebSocket socket)
{
// Read incoming message
var inputBytes = new byte[1024];
WebSocketReceiveResult result;
int total = 0;
do
{
result = await socket.ReceiveAsync(new ArraySegment<byte>(inputBytes), CancellationToken.None);
total += result.Count;
} while (result != null && !result.EndOfMessage);
return Encoding.UTF8.GetString(inputBytes, 0, total);
};
var incomingMessage = await receiveMessage(ws);
await Console.Out.WriteLineAsync($"Message received: [{incomingMessage}]");
var outgoingBytes = new byte[] { 4, 5, 6, 7 };
await ws.SendAsync(outgoingBytes, WebSocketMessageType.Binary, true, CancellationToken.None);
}
else if(ws.State == WebSocketState.Closed || ws.State == WebSocketState.Aborted)
{
break;
}
}
}
}
}

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

@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<IntDir>$(IntDir)$(TargetFramework)\</IntDir>
<OutDir>$(OutDir)$(TargetFramework)\</OutDir>
<BaseIntermediateOutputPath>$(MSBuildProjectExtensionsPath)</BaseIntermediateOutputPath>
</PropertyGroup>
<PropertyGroup Condition=" '$(RunConfiguration)' == 'https' " />
<PropertyGroup Condition=" '$(RunConfiguration)' == 'http' " />
<ItemGroup>
<None Remove="Facebook\" />
<None Remove="Facebook\React\" />
<None Remove="Facebook\React\Test\" />
</ItemGroup>
<ItemGroup>
<Folder Include="Facebook\" />
<Folder Include="Facebook\React\" />
<Folder Include="Facebook\React\Test\" />
</ItemGroup>
</Project>

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

@ -0,0 +1,17 @@
using System.Text;
namespace Microsoft.Office.Test
{
public sealed class OfficeJsTests
{
public static async Task Issue4144(HttpContext context)
{
var response = context.Response;
response.ContentType = "text/plain";
response.StatusCode = 200;
var bytes = Encoding.UTF8.GetBytes("Check headers: [Access-Control-Allow-Origin]");
await response.Body.WriteAsync(bytes);
}
}
}

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

@ -0,0 +1,51 @@
using System.Net.WebSockets;
using System.Text;
namespace Microsoft.React.Test
{
public sealed class WebSocketTests
{
static List<WebSocket> wsConnections = new List<WebSocket>();
public static async Task EchoSuffix(HttpContext context)
{
var announcement = @"This will send each incoming message back, with the string '_response' appended.";
await Console.Out.WriteLineAsync(announcement);
using var ws = await context.WebSockets.AcceptWebSocketAsync();
wsConnections.Add(ws);
while (true)
{
if (ws.State == WebSocketState.Open)
{
async Task<string> receiveMessage(WebSocket socket)
{
// Read incoming message
var inputBytes = new byte[1024];
WebSocketReceiveResult result;
int total = 0;
do
{
result = await socket.ReceiveAsync(new ArraySegment<byte>(inputBytes), CancellationToken.None);
total += result.Count;
} while (result != null && !result.EndOfMessage);
return Encoding.UTF8.GetString(inputBytes, 0, total);
};
var inputMessage = await receiveMessage(ws);
await Console.Out.WriteLineAsync($"Received message: {inputMessage}");
var outputMessage = $"{inputMessage}_response";
var outputBytes = Encoding.UTF8.GetBytes(outputMessage);
await ws.SendAsync(outputBytes, WebSocketMessageType.Text, true, CancellationToken.None);
}
else if (ws.State == WebSocketState.Closed || ws.State == WebSocketState.Aborted)
{
break;
}
}
}
}
}

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

@ -0,0 +1,71 @@
var builder = WebApplication.CreateBuilder(args);
// CORS middleware
//TODO: Subordinate to specific set of tests
var originPolicyName = "AllowedOrigins";
builder.Services.AddCors(
options =>
{
options.AddPolicy(
name: originPolicyName,
policy =>
{
policy
.WithOrigins("http://orig.in")
.WithMethods("GET")
;
});
});
var app = builder.Build();
app.UseWebSockets();
app.UseCors();
app.UseStaticFiles();
// See https://github.com/dotnet/aspnetcore/blob/v7.0.15/src/Http/Routing/src/RequestDelegateRouteBuilderExtensions.cs
// app.Map("/", () => "Sample HTTP Response");
async Task DefaultRequestDelegate(HttpContext context)
{
var response = context.Response;
response.StatusCode = 200;
response.ContentType = "text/plain";
var bytes = System.Text.Encoding.UTF8.GetBytes("Sample HTTP Response");
await response.Body.WriteAsync(bytes);
}
#region Request Mappings
app.Map("/", async context =>
{
if (context.WebSockets.IsWebSocketRequest)
{
// ws://localhost:5555
// See react-native/IntegrationTests/websocket_integration_test_server.js
// Note, the referred code has been removed in React Native 0.73
await Facebook.React.Test.RNTesterIntegrationTests.WebSocketTest(context);
}
else
{
await DefaultRequestDelegate(context);
}
});
app.Map(
"/rnw/rntester/websocketbinarytest",
Facebook.React.Test.RNTesterIntegrationTests.WebSocketBinaryTest
);
app.Map(
"/rnw/websockets/echosuffix",
Microsoft.React.Test.WebSocketTests.EchoSuffix
);
app.MapGet(
"/officedev/office-js/issues/4144",
Microsoft.Office.Test.OfficeJsTests.Issue4144)
.RequireCors(originPolicyName);
#endregion Request Mappings
await app.RunAsync();

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

@ -0,0 +1,37 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:5555",
"sslPort": 5543
}
},
"profiles": {
"https": {
"commandName": "Project",
"launchBrowser": true,
"applicationUrl": "https://localhost:5543;http://localhost:5555",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"dotnetRunMessages": true
},
"http": {
"commandName": "Project",
"launchBrowser": true,
"applicationUrl": "http://localhost:5555",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"dotnetRunMessages": true
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

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

@ -0,0 +1,75 @@
# Integration Test Website
This is a generic ASP.NET Core application that provides arbitrary HTTP responses and WebSocket endpoints to validate React Native Windows's functionality.
It is meant to complement (and partially replace) the in-process C++ test servers used for integration which have very limited functionality and are hard to program against.
This application enhances web testing via a number of features such as:
- Server-side Origin Policy (CORS) enforcement
- Static file serving
- HTTP authentication and authorization
- HTTP sessions
- Response caching
- Cookie handling
Deploying this website in Continuous Integration/Delivery environments also removes the dependency on remote web endpoints for end to end scenarios.
## Usage
### Developer Workflow
1. Build React Native Windows.
1. Start the Node Packager.
```pwsh
Set-Location vnext
npm run start
```
1. Trust the .NET-provided development SSL certificate:\
This should be a one-time step per .NET version.\
See https://learn.microsoft.com/en-us/aspnet/core/security/enforcing-ssl#trust-the-aspnet-core-https-development-certificate-on-windows-and-macos.
```cmd
dotnet dev-certs https --trust
```
1. Start this website.
```cmd
dotnet run --project vnext\TestWebSite
```
1. Run integration tests.
### Continuous Integration Workflow
The website gets deployed to a web server.\
This reduces the process management overhead and increases stability and availability in CI environments.
The website can also be installed on a development environment.\
*Note: This would require to update the website's publish directory with any new changes, but removes the need to manage the additonal process and terminal window.*
Here are the steps for Micrososoft's IIS:
1. Publish the website.
```pwsh
Set-Location vnext\TestWebSite
dotnet publish
```
1. Install IIS.
1. Install the .NET 7 SDK.\
https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/sdk-7.0.407-windows-x64-installer
1. Install the ASP.NET Core Hosting Bundle.\
https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/runtime-aspnetcore-8.0.3-windows-hosting-bundle-installer
1. Create or update a website that binds ports `5555` to `http` and `5543` to `https`.\
*For `https`, any trusted SSL certificate will work. There is no need to install `localhost.cicert`.*
1. Set the location to the publish directory (i.e. `C:\repo\react-native-windows\vnext\target\x64\Debug\Microsoft.ReactNative.Test.Website\Publish`)
## Technical Information
- The website is meant to run on ports `5555` (`http`, `ws`) and `5543` (`https`, `wss`).\
This can be modified via command line arguments or in [Properties/launchSettings.json](Properties/launchSettings.json).
- For encryption, self-signed PKCS12 certificate `localhost.cicert` is used (DevOps only).
The certificate is set to expire on January 1st, 2030.\
After that date, new one must be generated.
### Replacing the DevOps SSL certificate
1. Generate a new self-signed x509 web certificate.\
Use common name `CN=localhost`.
1. Replace the `localhost.cicert` with the new certificate.
1. Update the password in the Continuous Integration system.\
*The certificate password is mapped to DevOps variable `$(TestWebsiteCertPassword)`.*

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

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 25.0.1706.8
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.ReactNative.Test.Website", "..\Microsoft.ReactNative.Test.Website.csproj", "{E2DD641B-CA1C-4161-A00A-ADAACF4DF1AE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{E2DD641B-CA1C-4161-A00A-ADAACF4DF1AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E2DD641B-CA1C-4161-A00A-ADAACF4DF1AE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E2DD641B-CA1C-4161-A00A-ADAACF4DF1AE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E2DD641B-CA1C-4161-A00A-ADAACF4DF1AE}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {911C0A3A-86DF-41D8-8855-8459B78AB7E3}
EndGlobalSection
EndGlobal

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

@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}

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

@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}

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

@ -0,0 +1,6 @@
{
"version": 1,
"dependencies": {
"net7.0": {}
}
}

Двоичные данные
vnext/TestWebSite/wwwroot/static/react.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.6 KiB

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

@ -0,0 +1 @@
Sample Static Text File

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

@ -23,124 +23,40 @@ class BlobTest extends React.Component<{...}, State> {
state: State = {
statusCode: 0,
xhr: new XMLHttpRequest(),
// https://www.facebook.com/favicon.ico
// http://localhost:5555/static/react.png
// cspell:disable
expected:
'data:application/octet-stream;base64,' +
'AAABAAIAEBAAAAEAIABoBAAAJgAAACAgAAABACAAqBAAAI4EAAAoAAAAEAAAACAA' +
'AAABACAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOFl' +
'BiviZgKP4WYB1f//////////4WUA1eJmAI/hawYrAAAAAAAAAAAAAAAAAAAAAAAA' +
'AAAAAAAA/4ArBuNpA5TkawP942kC/+NpAv///////////+NpAv/jaQL/5GoD/eNp' +
'A5T/gCsGAAAAAAAAAAAAAAAA/4ArBuVvBL3lbgT/5W4E/+VuBP/lbgT/////////' +
'///lbgT/5W4E/+VuBP/lbgT/5W8Evf+AKwYAAAAAAAAAAOlzBZTncwX/53MF/+dz' +
'Bf/ncwX/53MF////////////53MF/+dzBf/ncwb/53MF/+dzBv/pcweUAAAAAO19' +
'DCvpeAf96HcH/+l4B//odwf/6XgH/+l4B////////////+h3B//odwf/6XgH/+h3' +
'B//peAf/6nkH/e19DCvrfQmP630J/+t9Cf/rfAn/630J/+t8Cf/rfAn/////////' +
'///rfQn/630J/+p8CP/rfQn/6nwI/+p8CP/rfQuP7YEL1e2BCv/tgQr/7IEK/+2B' +
'Cv/////////////////////////////////uiRj/7IEK/+2CCv/tggr/7YIM1e6G' +
'DfPvhgz/74YM/++HDP/vhgz/////////////////////////////////8Zw4/++G' +
'DP/uhgz/7oYM/+6GDPPwiw7z8IsN//CLDf/wiw3/8IsN//CLDf/wiw3/////////' +
'///wig3/8IoN//CLDf/wig3/8IsN//CLDf/xjA/z85EQ1fOQD//zkA//85AP//OQ' +
'D//zkA//85AP////////////8o8P//KPD//ykA//8o8P//KQD//ykA//85EQ1fSU' +
'EI/1lRH/9ZUR//SUEP/1lRH/9JQQ//SUEP/+9uz///////jDev/0mRz/9ZUR//SV' +
'Ef/1lRH/9ZUR//SUEI/5mhgr95kS/faZEv/2mRL/9pkS//aZEv/2mRL//Nqo////' +
'//////////////rLhv/3mhL/9pkS//eZEv35mhgrAAAAAPifFZT4nhT/+Z8U//ie' +
'FP/5nxT/+Z8U//ikI//83a3//vjw//78+f/7yX3/+J4T//ieFP/4nxWUAAAAAAAA' +
'AAD/qisG+6MWvfqjFf/6oxX/+qMV//qjFf/6oxX/+qMV//qjFf/6oxX/+qIV//qj' +
'Ff/7oxa9/6orBgAAAAAAAAAAAAAAAP+qKwb9qRiU/agW/fyoF//8qBf//agX//yo' +
'F//9qBf//agX//2oF/39qRiU/6orBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP+y' +
'Hiv/rRmP/6wZ1f+tGPP/rBjz/64Z1f+vGY//sh4rAAAAAAAAAAAAAAAAAAAAAPAP' +
'AADAAwAAgAEAAIABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAB' +
'AACAAQAAwAMAAPAPAAAoAAAAIAAAAEAAAAABACAAAAAAAAAQAAAAAAAAAAAAAAAA' +
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP+A' +
'AAbiZQRH4GMAlf//////////////////////////4GQAv+BjAJXiZQBH/4AABgAA' +
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAOpqCxjiZgKW4WYB8eJmAf/hZQH/////////' +
'///////////////////hZgH/4mYB/+FmAf/iZwHx4mYClupqCxgAAAAAAAAAAAAA' +
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP9t' +
'JAfkagSC42kC9ONoAv/jaAL/4mgC/+NoAv///////////////////////////+Jo' +
'Af/iaAL/4mgB/+JoAv/iaAL/42kC9ORqBIL/bSQHAAAAAAAAAAAAAAAAAAAAAAAA' +
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADqagsY5GoEx+NqA//jagP/42oD/+Nq' +
'A//kawP/42oD////////////////////////////42oD/+RrA//jagP/5GsD/+Rr' +
'A//kawP/5GsD/+RsBMfqdQsYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
'AAAAAAAA6HEGLeVuBOPlbQT/5GwD/+VtBP/kbAP/5GwD/+VtBP/kbAP/////////' +
'///////////////////kbAP/5G0D/+RsA//kbQP/5G0D/+RtA//kbQP/5G0D/+Ru' +
'A+PocQYtAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOp1CxjmcAbj5W8E/+Vv' +
'BP/lbwT/5W8E/+VvBP/lbwT/5W8E/+VvBP///////////////////////////+Vv' +
'BP/mcAX/5W8E/+ZwBf/mcAX/5W8E/+ZwBf/lbwT/5W8E/+ZwBuPqdQsYAAAAAAAA' +
'AAAAAAAAAAAAAAAAAAD/kiQH53IFx+ZyBf/mcQX/5nEF/+ZxBf/mcQX/5nEF/+Zx' +
'Bf/ncgX/5nEF////////////////////////////53IG/+ZxBf/ncgb/5nEF/+Zx' +
'Bf/mcgX/5nEF/+ZyBf/mcgX/5nEF/+dyBcf/kiQHAAAAAAAAAAAAAAAAAAAAAOd2' +
'CILodAb/53QG/+h0Bv/odAb/6HQG/+h0Bv/odAb/6HQG/+d0Bv/odAb/////////' +
'///////////////////ndAX/53QG/+d0Bf/ndAb/53QG/+h1Bv/ndAb/6HUG/+h1' +
'Bv/ndAX/6HUG/+d2BoIAAAAAAAAAAAAAAADqgAsY6HYG9Oh2B//odgb/6HYH/+h2' +
'B//odgb/6HYH/+h2Bv/odgb/6HYH/+h2Bv///////////////////////////+l3' +
'B//odgb/6XcH/+h2Bv/odgb/6HYH/+h2Bv/odgf/6HYH/+h2Bv/odgf/6HYG9OqA' +
'CxgAAAAAAAAAAOt6CZbpeQj/6nkI/+l5CP/qeQj/6nkI/+l5B//qeQj/6XkH/+l5' +
'B//peQf/6XkH////////////////////////////6XkI/+l5B//peQj/6XkH/+l5' +
'B//peQj/6XkH/+l5CP/peQj/6XkH/+l5CP/peQf/63oJlgAAAAD/gCsG7H0K8et8' +
'Cf/qewj/63wJ/+p7CP/qewj/6nsI/+p7CP/qewj/6nsI/+t8Cf/qewj/////////' +
'///////////////////qewj/6nwJ/+p7CP/qfAn/6nwJ/+p7CP/qfAn/6nsI/+p7' +
'CP/rfAn/6nsI/+t8Cf/sfQrx/4ArBu2BC0frfQn/630J/+t+Cf/rfQn/634J/+t+' +
'Cf/rfgn/634J////////////////////////////////////////////////////' +
'///////////////////zs27/634J/+x+Cf/rfgn/634J/+t+Cf/rfgn/634J/+t+' +
'Cf/tgQtH7IAKleyACv/sgAr/7IAK/+yACv/sgAr/7IAK/+yACv/sgAr/////////' +
'//////////////////////////////////////////////////////////////XC' +
'iv/sgAr/7IAK/+yACv/sgAr/7IAJ/+yACv/sgAn/7IAJ/+yACpXugwu/7YML/+2D' +
'C//tggr/7YML/+2CCv/tggr/7YIK/+2CCv//////////////////////////////' +
'////////////////////////////////////////+NKn/+2DC//tggr/7YML/+2D' +
'C//tgwv/7YML/+2DC//tgwv/7oMLv++GDNnuhQv/7oUL/+6FC//uhQv/7oUL/+6F' +
'C//vhQz/7oUL////////////////////////////////////////////////////' +
'///////////////////64cT/7oUL/+6FC//uhQv/7oUL/+6EC//uhQv/7oQL/+6E' +
'C//vhgzZ74gO8++IDP/viAz/74cM/++IDP/vhwz/74cM/++HDP/vhwz/////////' +
'//////////////////////////////////////////////////////////////3w' +
'4f/viA3/74cM/++IDf/viA3/74cM/++IDf/vhwz/74cM/++HDfPwiw7z8IoN//CK' +
'Df/wig3/8IoN//CKDf/wig3/8IkN//CKDf/wiQ3/8IkN//CKDf/wiQ3/////////' +
'///////////////////wiQ3/8IoN//CJDf/wig3/8IoN//CJDf/wig3/8IkN//CJ' +
'Df/wiQ3/8IkN//CJDf/wiQ3/8IsO8/KNDtnxjA7/8YwO//GMDf/xjA7/8YwN//GM' +
'Df/xjA3/8YwN//GMDf/xjA3/8YwO//GMDf////////////////////////////GM' +
'Dv/xjA7/8YwO//GMDv/xjA7/8YwO//GMDv/xjA7/8YwO//GMDv/xjA7/8YwO//GM' +
'Dv/yjQ7Z8o8Pv/KPD//yjw//8o8P//KPD//yjw//8o8P//KPD//yjw//8o8P//KP' +
'D//yjg7/8o8P////////////////////////////8Y4O//KODv/xjg7/8o4O//KO' +
'Dv/yjg7/8o4O//KODv/yjg7/8o8P//KODv/yjw//8o8P//OQEL/zkQ+V85EP//OR' +
'D//zkQ//85EP//ORD//zkQ//85EP//ORD//zkQ//85EP//OREP/zkQ///vr0////' +
'///////////////////0myb/85EQ//ORD//zkRD/85EQ//ORD//zkRD/85EP//OR' +
'D//zkQ//85EP//ORD//zkQ//85EPlfSXEkf0kxD/9JMQ//SUEP/0kxD/9JQQ//SU' +
'EP/zkxD/9JQQ//OTEP/zkxD/9JQQ//OTEP/86tD///////////////////////rV' +
'ov/1nSb/85MQ//STEP/0kxD/9JMQ//STEP/0kxD/9JMQ//SUEP/0kxD/9JQQ//SU' +
'EP/0kxJH/6orBvWWEvH1lhH/9ZYR//WWEf/1lhH/9ZYR//WWEf/1lhH/9ZYR//WW' +
'Ef/1lhH/9ZYR//vZq///////////////////////////////////////////////' +
'///1lhH/9ZYR//WWEf/1lhH/9ZYR//WWEf/1lhH/9ZYS8f+qKwYAAAAA95kTlvaY' +
'Ev/2mBH/9pgS//aYEf/2mBH/9ZgR//aYEf/1mBH/9ZgR//aYEv/1mBH/+LFN////' +
'//////////////////////////////////////////////aYEv/1mBH/9pgS//aY' +
'Ev/1mBH/9pgS//WYEf/3mRGWAAAAAAAAAAD/nxUY+JwU9PebE//3mxP/95sT//eb' +
'E//3mxP/95sT//ebE//3mxP/95oS//ebE//3mhL//OK7////////////////////' +
'////////////////////////95sT//ebE//3mxP/95sT//aaEv/3mxP/95sT9P+f' +
'FRgAAAAAAAAAAAAAAAD5nxSC+J0T//idE//4nRP/+J0T//ecE//4nRP/95wT//ec' +
'E//4nRP/95wT//idE//4pSf//efF////////////////////////////////////' +
'///4nRP/950T//idE//4nRP/+J0T//idE//5nxSCAAAAAAAAAAAAAAAAAAAAAP+2' +
'JAf6oBXH+aAU//mgFP/5oBT/+J8U//mgFP/4nxT/+J8U//mfFP/4nxT/+Z8U//mf' +
'FP/5oRf/+86H//7w2v/+/Pj//v36//758f/+8+P//evQ//mgFP/5nxT/+aAU//mg' +
'FP/4nxT/+qAVx/+2JAcAAAAAAAAAAAAAAAAAAAAAAAAAAP+qFRj7oxXj+aEU//mh' +
'FP/6ohX/+aEU//qiFf/6ohX/+qIV//qiFf/6ohX/+qIV//mhFP/6ohX/+aEU//mh' +
'FP/6ohX/+aEU//qiFf/6ohX/+aEU//qiFf/5oRT/+aEU//ujFeP/qhUYAAAAAAAA' +
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP+mFi78pBXj+6QV//ukFv/7pBX/+6QW//uk' +
'Fv/6pBX/+6QW//qkFf/6pBX/+6QW//qkFf/7pBb/+6QW//ulFv/7pBb/+6UW//ul' +
'Fv/7pBX/+6UW//ukFf/8pBXj/6QXLQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
'AAAAAAAAAAAAAP+qIBj8qBfH/KcW//ynF//8pxb//KcW//ynFv/8pxb//KcW//yn' +
'Fv/7phb//KcW//umFv/7phb/+6YW//umFv/7phb/+6YW//ynFv/7phb//KgXx/+q' +
'IBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP+2' +
'JAf9qxiC/akY9PypF//8qRf//KgX//ypF//8qBf//KgX//2pF//8qBf//akX//2p' +
'F//9qRf//akX//2pF//9qRf//qkY9P2rGIL/tiQHAAAAAAAAAAAAAAAAAAAAAAAA' +
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/tSAY/60alv+s' +
'GPH+rBj//qwY//6sGP/+rBj//asY//6sGP/9qxj//asY//2rF//9qxj//qsX8f2s' +
'GJb/tSAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/9UrBv+wGUf/rxqV/68Zv/+v' +
'Gtn/rhnz/64Z8/+vGtn/rxm//68alf+wGUf/1SsGAAAAAAAAAAAAAAAAAAAAAAAA' +
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/AA///AAD//AAAP/gAAB/wAAAP4AAAB8AA' +
'AAPAAAADgAAAAYAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
'AAAAAAAAAAAAAAAAAACAAAABgAAAAcAAAAPAAAAD4AAAB/AAAA/4AAAf/AAAP/8A' +
'AP//wAP/',
'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' +
'uP2D2H8BsGL5W7blULYAAAAASUVORK5CYII=',
// cspell:enable
};
@ -150,7 +66,7 @@ class BlobTest extends React.Component<{...}, State> {
statusCode: this.state.xhr.status,
});
};
this.state.xhr.open('GET', 'https://www.facebook.com/favicon.ico');
this.state.xhr.open('GET', 'http://localhost:5555/static/react.png');
this.state.xhr.setRequestHeader('Accept-Encoding', 'utf-8');
this.state.xhr.responseType = 'blob';
this.state.xhr.send();

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

@ -16,7 +16,7 @@ const {AppRegistry, View} = ReactNative;
const {TestModule} = ReactNative.NativeModules;
// eslint-disable-next-line @microsoft/sdl/no-insecure-url
const DEFAULT_WS_URL = 'ws://localhost:5557/';
const DEFAULT_WS_URL = 'ws://localhost:5555/rnw/rntester/websocketbinarytest';
const WS_EVENTS = ['close', 'error', 'message', 'open'];