feat(windows): Add POST requests, fixes Windows CI issues, and other QOL (#1926)

* Added POST request support for Windows.

* Cleanup formatting for docs

* Updated test certificate

* Reverted publisher name and fixed password mismatch

* Fixes to Windows tests

* Remove winappdriver install

* Run react-native server in background

* Added url encoded form support

* Added support for custom headers

Co-authored-by: Kennedy Mumo <kemumo@microsoft.com>
This commit is contained in:
John Kennedy Mumo 2021-04-13 16:40:49 -07:00 committed by GitHub
parent 69e56c7911
commit d352d147bd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 97 additions and 36 deletions

View File

@ -54,6 +54,10 @@ jobs:
- name: Start Appium server
shell: powershell
run: Start-Process PowerShell -ArgumentList "yarn appium"
- name: Start React server
shell: powershell
run: Start-Process PowerShell -ArgumentList "yarn start:windows"
- name: Run tests
run: yarn test:windows

View File

@ -4,28 +4,23 @@
*/
import { driver, By2 } from 'selenium-appium'
import { until } from 'selenium-webdriver';
const setup = require('../jest-setups/jest.setup');
jest.setTimeout(50000);
jest.setTimeout(150000);
beforeAll(() => {
return driver.startWithCapabilities(setup.capabilites);
});
afterAll(() => {
return driver.quit();
});
const WindowsApplicationDriverUrl = "http://127.0.0.1:4723/wd/hub";
describe('Alert Tests', () => {
test('Show Alert', async () => {
const showAlertButton = await driver.wait(until.elementLocated(By2.nativeName('Show alert')));
await driver.startWithCapabilities(setup.capabilities, WindowsApplicationDriverUrl);
const showAlertButton = By2.nativeName('Show alert');
await showAlertButton.click();
await driver.wait(until.elementLocated(By2.nativeName('Hello! I am an alert box!')));
await By2.nativeName('OK').click();
const dismissMessage = await driver.wait(until.elementLocated(By2.nativeName('Alert dismissed!')));
await By2.nativeName('Hello! I am an alert box!');
// await By2.nativeName('OK').click(); All alerts will be automatically dismissed as Windows Webview does not have support for Alerts https://github.com/MicrosoftDocs/winrt-api/blob/docs/windows.ui.xaml.controls/webview.md#use-of-alert
const dismissMessage = By2.nativeName('Alert dismissed!');
expect(dismissMessage).not.toBeNull();
await driver.quit();
});
});

View File

@ -60,11 +60,12 @@ Autolinking is not yet supported for ReactNativeWindows. Make following addition
#### **windows/myapp.sln**
Add the `ReactNativeWebView` project to your solution.
Add the `ReactNativeWebView` and `WebViewBridgeComponent` project to your solution.
1. Open the solution in Visual Studio 2019
2. Right-click Solution icon in Solution Explorer > Add > Existing Project
Select `node_modules\react-native-webview\windows\ReactNativeWebView\ReactNativeWebView.vcxproj`
Select `node_modules\react-native-webview\windows\WebViewBridgeComponent\WebViewBridgeComponent.vcxproj`
#### **windows/myapp/myapp.vcxproj**

View File

@ -323,6 +323,7 @@ _Under the hood_
> On iOS, ~~`injectedJavaScript` runs a method on WebView called `evaluateJavaScript:completionHandler:`~~ this is no longer true as of version `8.2.0`. Instead, we use a `WKUserScript` with injection time `WKUserScriptInjectionTimeAtDocumentEnd`. As a consequence, `injectedJavaScript` no longer returns an evaluation value nor logs a warning to the console. In the unlikely event that your app depended upon this behaviour, please see migration steps [here](https://github.com/react-native-webview/react-native-webview/pull/1119#issuecomment-574919464) to retain equivalent behaviour.
> On Android, `injectedJavaScript` runs a method on the Android WebView called `evaluateJavascriptWithFallback`
> On Windows, `injectedJavaScript` runs a method on the WinRT/C++ WebView called `InvokeScriptAsync`
#### The `injectedJavaScriptBeforeContentLoaded` prop

View File

@ -106,9 +106,9 @@ The object passed to `source` can have either of the following shapes:
**Load uri**
- `uri` (string) - The URI to load in the `WebView`. Can be a local or remote file, and can be changed with React state or props to navigate to a new page.
- `method` (string) - The HTTP Method to use. Defaults to GET if not specified. On Android, the only supported methods are GET and POST.
- `method` (string) - The HTTP Method to use. Defaults to GET if not specified. On Android and Windows, the only supported methods are GET and POST.
- `headers` (object) - Additional HTTP headers to send with the request. On Android, this can only be used with GET requests. See the [Guide](Guide.md#setting-custom-headers) for more information on setting custom headers.
- `body` (string) - The HTTP body to send with the request. This must be a valid UTF-8 string, and will be sent exactly as specified, with no additional encoding (e.g. URL-escaping or base64) applied. On Android, this can only be used with POST requests.
- `body` (string) - The HTTP body to send with the request. This must be a valid UTF-8 string, and will be sent exactly as specified, with no additional encoding (e.g. URL-escaping or base64) applied. On Android and Windows, this can only be used with POST requests.
**Static HTML**
@ -152,12 +152,14 @@ Make sure the string evaluates to a valid type (`true` works) and doesn't otherw
On iOS, see [`WKUserScriptInjectionTimeAtDocumentEnd`](https://developer.apple.com/documentation/webkit/wkuserscriptinjectiontime/wkuserscriptinjectiontimeatdocumentend?language=objc). Be sure
to set an [`onMessage`](Reference.md#onmessage) handler, even if it's a no-op, or the code will not be run.
| Type | Required | Platform |
| ------ | -------- | ------------------- |
| string | No | iOS, Android, macOS |
| Type | Required | Platform |
| ------ | -------- | ---------------------------- |
| string | No | iOS, Android, macOS, Windows |
To learn more, read the [Communicating between JS and Native](Guide.md#communicating-between-js-and-native) guide.
_Kindly note: Windows does not have [native support for alerts](https://github.com/MicrosoftDocs/winrt-api/blob/docs/windows.ui.xaml.controls/webview.md#use-of-alert), as such any scripts to show an alert will not work._
Example:
Post message a JSON object of `window.location` to be handled by [`onMessage`](Reference.md#onmessage)
@ -597,8 +599,8 @@ url
Function that is invoked when the scroll event is fired in the `WebView`.
| Type | Required | Platform |
| -------- | -------- | ----------------------- |
| Type | Required | Platform |
| -------- | -------- | ---------------------------- |
| function | No | iOS, macOS, Android, Windows |
Example:

View File

@ -47,7 +47,7 @@ EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
..\..\node_modules\react-native-windows\JSI\Shared\JSI.Shared.vcxitems*{0cc28589-39e4-4288-b162-97b959f8b843}*SharedItemsImports = 9
..\..\node_modules\react-native-windows\ReactWindowsCore\ReactWindowsCore.vcxitems*{11c084a3-a57c-4296-a679-cac17b603144}*SharedItemsImports = 4
..\..\node_modules\react-native-windows\ReactWindowsCore\ReactWindowsCore-Items.vcxitems*{11c084a3-a57c-4296-a679-cac17b603144}*SharedItemsImports = 4
..\..\node_modules\react-native-windows\Shared\Shared.vcxitems*{2049dbe9-8d13-42c9-ae4b-413ae38fffd0}*SharedItemsImports = 9
..\..\node_modules\react-native-windows\Microsoft.ReactNative.SharedManaged\Microsoft.ReactNative.SharedManaged.projitems*{67a1076f-7790-4203-86ea-4402ccb5e782}*SharedItemsImports = 13
..\..\node_modules\react-native-windows\Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems*{729d9af8-cd9e-4427-9f6c-fb757e287729}*SharedItemsImports = 4
@ -57,7 +57,6 @@ Global
..\..\node_modules\react-native-windows\Chakra\Chakra.vcxitems*{c38970c0-5fbf-4d69-90d8-cbac225ae895}*SharedItemsImports = 9
..\..\node_modules\react-native-windows\Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems*{da8b35b3-da00-4b02-bde6-6a397b3fd46b}*SharedItemsImports = 9
..\..\node_modules\react-native-windows\Chakra\Chakra.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4
..\..\node_modules\react-native-windows\JSI\Shared\JSI.Shared.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4
..\..\node_modules\react-native-windows\Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4
..\..\node_modules\react-native-windows\Mso\Mso.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4
..\..\node_modules\react-native-windows\Shared\Shared.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4

View File

@ -16,9 +16,9 @@
<WindowsTargetPlatformVersion Condition=" '$(WindowsTargetPlatformVersion)' == '' ">10.0.18362.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformMinVersion>10.0.15063.0</WindowsTargetPlatformMinVersion>
<PackageCertificateKeyFile>WebViewWindows_TemporaryKey.pfx</PackageCertificateKeyFile>
<PackageCertificateThumbprint>82A0D300B0912A62746FFB3E6E04F88985BC2798</PackageCertificateThumbprint>
<PackageCertificatePassword>password</PackageCertificatePassword>
<AppxPackageSigningEnabled>true</AppxPackageSigningEnabled>
<PackageCertificateThumbprint>1DA6E34911B18C433FE3E543D0429FC808468C89</PackageCertificateThumbprint>
<PackageCertificatePassword></PackageCertificatePassword>
<AppxPackageSigningEnabled>True</AppxPackageSigningEnabled>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<ItemGroup Label="ProjectConfigurations">
@ -170,6 +170,7 @@
<Import Project="$(SolutionDir)packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('$(SolutionDir)packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets')" />
<Import Project="$(SolutionDir)packages\Microsoft.UI.Xaml.2.3.191129002\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('$(SolutionDir)packages\Microsoft.UI.Xaml.2.3.191129002\build\native\Microsoft.UI.Xaml.targets')" />
</ImportGroup>
<Target Name="Deploy" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>

View File

@ -1,10 +1,12 @@
import { windowsAppDriverCapabilities } from 'selenium-appium'
const { platform } = require('./jest.setup.windows');
switch (platform) {
case "windows":
const webViewWindowsAppId = 'WebViewWindows_3x6rhkkr9xcf6!App';
module.exports = {
capabilites: windowsAppDriverCapabilities(webViewWindowsAppId)
capabilities: windowsAppDriverCapabilities(webViewWindowsAppId)
}
break;
default:

View File

@ -1 +1 @@
platform = "windows"
export const platform = "windows"

View File

@ -22,7 +22,7 @@
"build": "yarn tsc",
"prepare": "yarn build",
"appium": "appium",
"test:windows": "yarn jest --setupFiles=./jest-setups/jest.setup.windows.js"
"test:windows": "yarn jest --setupFiles=./jest-setups/jest.setup.js"
},
"rn-docs": {
"title": "Webview",
@ -67,10 +67,11 @@
"react-native": "0.62.2",
"react-native-macos": "0.60.0-microsoft.73",
"react-native-windows": "0.62.17",
"selenium-appium": "0.0.15",
"selenium-appium": "1.0.2",
"selenium-webdriver": "4.0.0-alpha.7",
"semantic-release": "15.13.24",
"typescript": "3.8.3"
"typescript": "3.8.3",
"winappdriver": "^0.0.7"
},
"repository": {
"type": "git",

View File

@ -4,6 +4,7 @@
#include "ReactWebView.h"
#include "JSValueXaml.h"
namespace winrt {
using namespace Microsoft::ReactNative;
using namespace Windows::Foundation;
@ -11,6 +12,8 @@ namespace winrt {
using namespace Windows::UI;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::Web::Http;
using namespace Windows::Web::Http::Headers;
}
namespace winrt::ReactNativeWebView::implementation {
@ -75,7 +78,52 @@ namespace winrt::ReactNativeWebView::implementation {
uriString.replace(0, 7, bundleRootPath.empty() ? "ms-appx-web:///Bundle/" : bundleRootPath);
}
webView.Navigate(winrt::Uri(to_hstring(uriString)));
bool hasHeaders = srcMap.find("headers") != srcMap.end();
auto httpRequest = winrt::HttpRequestMessage();
httpRequest.RequestUri(winrt::Uri(to_hstring(uriString)));
if (srcMap.find("method") != srcMap.end() && srcMap.at("method").AsString() == "POST")
{
httpRequest.Method(winrt::HttpMethod::Post());
auto formBody = srcMap.at("body").AsString();
bool isUrlEncodedForm = hasHeaders &&
srcMap.at("headers").AsObject().find("content-type") !=
srcMap.at("headers").AsObject().end() &&
srcMap.at("headers").AsObject().at("content-type") == "application/x-www-form-urlencoded";
if (isUrlEncodedForm)
{
auto formContent = winrt::single_threaded_observable_map<winrt::hstring, winrt::hstring>();
auto counter = 0;
auto current = formBody.find_first_of("&");
while (counter <= formBody.find_last_of("&"))
{
auto keyValueSeparator = formBody.substr(counter, counter + current).find('=');
if (keyValueSeparator <= current)
{
auto key = winrt::to_hstring(formBody.substr(counter, keyValueSeparator));
auto value = winrt::to_hstring(formBody.substr(
keyValueSeparator + counter + 1, current - keyValueSeparator - 1));
formContent.Insert(key, value);
}
counter += current + 1;
current = formBody.substr(counter, formBody.size() - counter).find_first_of("&");
}
httpRequest.Content(winrt::HttpFormUrlEncodedContent(formContent));
httpRequest.Headers().Accept().TryParseAdd(L"application/x-www-form-urlencoded");
}
else
{
httpRequest.Content(winrt::HttpStringContent(to_hstring(formBody)));
}
}
if (hasHeaders) {
for (auto const& header : srcMap.at("headers").AsObject()) {
auto const& headerKey = header.first;
auto const& headerValue = header.second;
if (headerValue.IsNull()) continue;
httpRequest.Headers().TryAppendWithoutValidation(winrt::to_hstring(headerKey), winrt::to_hstring(headerValue.AsString()));
}
}
webView.NavigateWithHttpRequestMessage(httpRequest);
}
else if (srcMap.find("html") != srcMap.end()) {
auto htmlString = srcMap.at("html").AsString();

View File

@ -10,4 +10,6 @@
#include <winrt/Windows.UI.Xaml.Controls.h>
#include <winrt/Windows.UI.Xaml.Markup.h>
#include <winrt/Windows.UI.Xaml.Navigation.h>
#include <winrt/Windows.Web.Http.h>
#include <winrt/Windows.Web.Http.Headers.h>
#include <winrt/Microsoft.ReactNative.h>

View File

@ -11689,10 +11689,10 @@ scheduler@0.17.0:
loose-envify "^1.1.0"
object-assign "^4.1.1"
selenium-appium@0.0.15:
version "0.0.15"
resolved "https://registry.yarnpkg.com/selenium-appium/-/selenium-appium-0.0.15.tgz#27eacd40ebddc1f4af00a1c50278a394e420e2ef"
integrity sha512-9/DGdpC8TF88h2eOaFoLIwNDG16He5o2CZOOoaeV1gwNKpkvcpCCA6SjIxgHbWm/0vGzn8TUdmbAlszIoQQzQg==
selenium-appium@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/selenium-appium/-/selenium-appium-1.0.2.tgz#78f274c61c2edd4837ef9ffc8c855d70e5b01f29"
integrity sha512-+aIvzAoydWhJSfsLd0fdIq7D9eas2Ck7DQxT18fe2bnm5TZE6j+2DaOVK6vUrSp/uUuG+KB9RfAuxfUXQqVPFg==
selenium-webdriver@3.x:
version "3.6.0"
@ -13297,6 +13297,11 @@ widest-line@^2.0.0:
dependencies:
string-width "^2.1.1"
winappdriver@^0.0.7:
version "0.0.7"
resolved "https://registry.yarnpkg.com/winappdriver/-/winappdriver-0.0.7.tgz#77c730b1f321c7b0f389612867ae2ef8d4121e82"
integrity sha512-Tq9BGwWmnsSdIjMIDtfH5/mdn4Qk2FO5FYAhAcoL0kZByHVtleCwoCFoLG814b4a4BEbVOizuMgY6x7bTFVY/g==
windows-release@^3.1.0:
version "3.3.3"
resolved "https://registry.yarnpkg.com/windows-release/-/windows-release-3.3.3.tgz#1c10027c7225743eec6b89df160d64c2e0293999"