Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .ado/build-template.yml
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@ extends:
#12714 - Disable for first deployment of test website.
- name: Desktop.IntegrationTests.Filter
value: >
(FullyQualifiedName!~Microsoft::React::Test::RNTesterHeadlessTests)&
(FullyQualifiedName!=Microsoft::React::Test::WebSocketIntegrationTest::ConnectClose)&
(FullyQualifiedName!=Microsoft::React::Test::WebSocketIntegrationTest::ConnectNoClose)&
(FullyQualifiedName!=Microsoft::React::Test::WebSocketIntegrationTest::SendReceiveClose)&
Expand Down
6 changes: 0 additions & 6 deletions .ado/jobs/desktop-single.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,6 @@ steps:

- template: ../templates/apply-published-version-vars.yml

- ${{ if eq(variables['Desktop.IntegrationTests.SkipRNTester'], true) }}:
- pwsh: |
$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

- template: ../templates/msbuild-sln.yml
parameters:
solutionDir: vnext
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "Re-introduce WebSocket JS integration tests",
"packageName": "react-native-windows",
"email": "julio.rocha@microsoft.com",
"dependentChangeType": "patch"
}
104 changes: 54 additions & 50 deletions vnext/Desktop.IntegrationTests/RNTesterHeadlessTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <MddBootstrap.h>
#include <WindowsAppSDK-VersionInfo.h>

#include <CppRuntimeOptions.h>
#include "Modules/TestModule.h"
#include "TestReactNativeHostHolder.h"

Expand All @@ -17,6 +18,35 @@ namespace msrn = winrt::Microsoft::ReactNative;

namespace Microsoft::React::Test {

namespace {
void RunTest(std::wstring_view jsBundle) {
TestModule::Reset();

winrt::handle instanceLoadedEvent{CreateEvent(nullptr, TRUE, FALSE, nullptr)};
bool instanceFailed{false};

auto holder = TestReactNativeHostHolder(
jsBundle, [&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

TEST_CLASS (RNTesterHeadlessTests) {
TEST_CLASS_INITIALIZE(Initialize) {
// https://learn.microsoft.com/en-us/windows/windows-app-sdk/api/win32/mddbootstrap/nf-mddbootstrap-mddbootstrapinitialize2
Expand All @@ -37,61 +67,35 @@ TEST_CLASS (RNTesterHeadlessTests) {
}

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());
}
RunTest(L"IntegrationTests/DummyTest");
}

TEST_METHOD(Fetch) {
RunTest(L"IntegrationTests/FetchTest");
}

auto status = TestModule::AwaitCompletion();
Assert::IsTrue(status == TestStatus::Passed, L"Test did not pass (JS did not call markTestPassed within timeout)");
TEST_METHOD(XHR) {
RunTest(L"IntegrationTests/XHRTest");
}

TEST_METHOD(WebSocket) {
RunTest(L"IntegrationTests/WebSocketTest");
}

TEST_METHOD(WebSocketBlob) {
RunTest(L"IntegrationTests/WebSocketBlobTest");
}

BEGIN_TEST_METHOD_ATTRIBUTE(WebSocketArrayBuffer)
TEST_IGNORE()
END_TEST_METHOD_ATTRIBUTE()
TEST_METHOD(WebSocketArrayBuffer) {
TestModule::Reset();

winrt::handle instanceLoadedEvent{CreateEvent(nullptr, TRUE, FALSE, nullptr)};
bool instanceFailed{false};

auto holder = TestReactNativeHostHolder(
L"IntegrationTests/WebSocketArrayBufferTest",
[&instanceLoadedEvent, &instanceFailed](msrn::ReactNativeHost const &host) noexcept {
host.InstanceSettings().InstanceLoaded(
[&instanceLoadedEvent, &instanceFailed](auto const &, msrn::InstanceLoadedEventArgs args) noexcept {
instanceFailed = args.Failed();
SetEvent(instanceLoadedEvent.get());
});
});

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());
}
RunTest(L"IntegrationTests/WebSocketArrayBufferTest");
}

TEST_METHOD(WebSocketMultipleSend) {
RunTest(L"IntegrationTests/WebSocketMultipleSendTest");
}

auto status = TestModule::AwaitCompletion();
Assert::IsTrue(status == TestStatus::Passed, L"Test did not pass (JS did not call markTestPassed within timeout)");
TEST_METHOD(Blob) {
RunTest(L"IntegrationTests/BlobTest");
}
};

Expand Down
2 changes: 1 addition & 1 deletion vnext/TestWebSite/wwwroot/static/sample.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Sample Static Text File
Sample Static Text File
12 changes: 4 additions & 8 deletions vnext/overrides.json
Original file line number Diff line number Diff line change
Expand Up @@ -248,14 +248,6 @@
"type": "platform",
"file": "src-win/IntegrationTests/LoggingTest.js"
},
{
"type": "platform",
"file": "src-win/IntegrationTests/websocket_integration_test_server_binary.js"
},
{
"type": "platform",
"file": "src-win/IntegrationTests/websocket_integration_test_server_blob.js"
},
{
"type": "platform",
"file": "src-win/IntegrationTests/WebSocketArrayBufferTest.js"
Expand All @@ -268,6 +260,10 @@
"type": "platform",
"file": "src-win/IntegrationTests/WebSocketBlobTest.js"
},
{
"type": "platform",
"file": "src-win/IntegrationTests/WebSocketTest.js"
},
{
"type": "platform",
"file": "src-win/IntegrationTests/WebSocketMultipleSendTest.js"
Expand Down
161 changes: 62 additions & 99 deletions vnext/src-win/IntegrationTests/BlobTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,115 +2,78 @@
* Copyright (c) Microsoft Corporation.
* Licensed under the MIT License.
* @format
* @flow
*/
'use strict';

const React = require('react');
const ReactNative = require('react-native');
const {TurboModuleRegistry} = require('react-native');

const {AppRegistry, View} = ReactNative;
const TestModule = TurboModuleRegistry.get('TestModule');

const {TestModule} = ReactNative.NativeModules;

type State = {
statusCode: number,
xhr: XMLHttpRequest,
expected: string,
};

class BlobTest extends React.Component<{...}, State> {
state: State = {
statusCode: 0,
xhr: new XMLHttpRequest(),
// http://localhost:5555/static/react.png
// cspell:disable
expected:
'data:application/octet-stream;base64,' +
'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' +
'uP2D2H8BsGL5W7blULYAAAAASUVORK5CYII=',
// cspell:enable
};
if (!TestModule) {
throw new Error('TestModule is not available');
}

_get = () => {
this.state.xhr.onloadend = () => {
this.setState({
statusCode: this.state.xhr.status,
});
};
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();
};
const URL = 'http://localhost:5555/static/react.png';

_getSucceeded = (): boolean => {
return this.state.statusCode === 200 && this.state.xhr.response !== null;
};
// cspell:disable
const EXPECTED_DATA_URL =
'data:application/octet-stream;base64,' +
'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' +
'uP2D2H8BsGL5W7blULYAAAAASUVORK5CYII=';
// cspell:enable

_waitFor = (condition: any, timeout: any, callback: any) => {
let remaining = timeout;
const timeoutFunction = function () {
if (condition()) {
callback(true);
return;
}
remaining--;
if (remaining === 0) {
callback(false);
} else {
setTimeout(timeoutFunction, 1000);
}
};
setTimeout(timeoutFunction, 1000);
};
const xhr = new XMLHttpRequest();
xhr.responseType = 'blob';

componentDidMount() {
this._get();
this._waitFor(this._getSucceeded, 6, doneSucceeded => {
let reader = new FileReader();
reader.readAsDataURL(this.state.xhr.response);
reader.onload = () => {
TestModule.markTestPassed(
doneSucceeded && this.state.expected === reader.result,
);
};
});
xhr.onloadend = () => {
const succeeded = xhr.status === 200 && xhr.response !== null;
if (!succeeded) {
TestModule.markTestPassed(false);
return;
}

render(): React.Node {
return <View />;
}
}
const reader = new FileReader();
reader.onload = () => {
TestModule.markTestPassed(reader.result === EXPECTED_DATA_URL);
};
reader.onerror = () => {
TestModule.markTestPassed(false);
};
reader.readAsDataURL(xhr.response);
};

AppRegistry.registerComponent('BlobTest', () => BlobTest);
xhr.onerror = () => {
TestModule.markTestPassed(false);
};

module.exports = BlobTest;
xhr.open('GET', URL);
xhr.setRequestHeader('Accept-Encoding', 'utf-8');
xhr.send();
Loading
Loading