diff --git a/change/react-native-windows-2020-04-29-03-21-18-testhook.json b/change/react-native-windows-2020-04-29-03-21-18-testhook.json
new file mode 100644
index 00000000000..3e1c6f1a455
--- /dev/null
+++ b/change/react-native-windows-2020-04-29-03-21-18-testhook.json
@@ -0,0 +1,8 @@
+{
+ "type": "prerelease",
+ "comment": "Refactor TestHook out of ViewManagerBase and special case layout properties",
+ "packageName": "react-native-windows",
+ "email": "asklar@microsoft.com",
+ "dependentChangeType": "patch",
+ "date": "2020-04-29T10:21:18.921Z"
+}
diff --git a/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj b/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj
index c5e68931833..57d6d88ea13 100644
--- a/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj
+++ b/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj
@@ -331,6 +331,7 @@
+
@@ -488,6 +489,7 @@
+
diff --git a/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj.filters b/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj.filters
index 3b221e531d0..e53f5484d2f 100644
--- a/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj.filters
+++ b/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj.filters
@@ -92,9 +92,6 @@
Modules
-
- Modules
-
Modules
@@ -318,6 +315,8 @@
Views
+
+
@@ -410,9 +409,6 @@
Modules
-
- Modules
-
Modules
@@ -674,6 +670,8 @@
Views
+
+
diff --git a/vnext/Microsoft.ReactNative/TestHook.cpp b/vnext/Microsoft.ReactNative/TestHook.cpp
new file mode 100644
index 00000000000..dc686a34c3f
--- /dev/null
+++ b/vnext/Microsoft.ReactNative/TestHook.cpp
@@ -0,0 +1,103 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+#include "pch.h"
+#include "TestHook.h"
+#include
+
+#ifdef DEBUG
+
+// Obtained from https://reactnative.dev/docs/layout-props
+// See getLayoutProps.ps1 next to this file.
+std::vector TestHook::layoutProperties = {
+ "alignContent",
+ "alignItems",
+ "alignSelf",
+ "aspectRatio",
+ "borderBottomWidth",
+ "borderEndWidth",
+ "borderLeftWidth",
+ "borderRightWidth",
+ "borderStartWidth",
+ "borderTopWidth",
+ "borderWidth",
+ "bottom",
+ "direction",
+ "display",
+ "end",
+ "flex",
+ "flexBasis",
+ "flexDirection",
+ "flexGrow",
+ "flexShrink",
+ "flexWrap",
+ "height",
+ "justifyContent",
+ "left",
+ "margin",
+ "marginBottom",
+ "marginEnd",
+ "marginHorizontal",
+ "marginLeft",
+ "marginRight",
+ "marginStart",
+ "marginTop",
+ "marginVertical",
+ "maxHeight",
+ "maxWidth",
+ "minHeight",
+ "minWidth",
+ "overflow",
+ "padding",
+ "paddingBottom",
+ "paddingEnd",
+ "paddingHorizontal",
+ "paddingLeft",
+ "paddingRight",
+ "paddingStart",
+ "paddingTop",
+ "paddingVertical",
+ "position",
+ "right",
+ "start",
+ "top",
+ "width",
+ "zIndex",
+};
+
+void TestHook::NotifyUnimplementedProperty(
+ const std::string &viewManager,
+ const std::string &reactClassName,
+ const std::string &propertyName,
+ const folly::dynamic &propertyValue) {
+ if (std::find(layoutProperties.begin(), layoutProperties.end(), propertyName) != layoutProperties.end()) {
+ return;
+ }
+ std::string value;
+ size_t size{};
+ try {
+ if (propertyValue.isObject()) {
+ value = "[Object]";
+ } else if (propertyValue.isNull()) {
+ value = "[Null]";
+ } else if (propertyValue.isArray()) {
+ size = propertyValue.size();
+ value = "[Array]";
+ } else {
+ value = propertyValue.asString();
+ }
+ } catch (const folly::TypeError &e) {
+ value = e.what();
+ }
+
+ cdebug << "[UnimplementedProperty] ViewManager = " << viewManager << " elementClass = " << reactClassName
+ << " propertyName = " << propertyName << " value = " << value;
+
+ if (size != 0) {
+ cdebug << " (" << size << " elems)";
+ }
+
+ cdebug << std::endl;
+ // DebugBreak();
+}
+
+#endif // DEBUG
diff --git a/vnext/Microsoft.ReactNative/TestHook.h b/vnext/Microsoft.ReactNative/TestHook.h
new file mode 100644
index 00000000000..c5dc3983a1c
--- /dev/null
+++ b/vnext/Microsoft.ReactNative/TestHook.h
@@ -0,0 +1,15 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+#pragma once
+#include
+#include
+#include
+
+struct TestHook {
+ static void NotifyUnimplementedProperty(
+ const std::string &viewManager,
+ const std::string &reactClassName,
+ const std::string &propertyName,
+ const folly::dynamic &propertyValue);
+ static std::vector layoutProperties;
+};
diff --git a/vnext/Microsoft.ReactNative/getLayoutProps.ps1 b/vnext/Microsoft.ReactNative/getLayoutProps.ps1
new file mode 100644
index 00000000000..0a222f0219e
--- /dev/null
+++ b/vnext/Microsoft.ReactNative/getLayoutProps.ps1
@@ -0,0 +1,5 @@
+# This script produces the values for the layoutProperties vector
+# in TestHook.cpp
+$page = Invoke-WebRequest "https://reactnative.dev/docs/layout-props"
+$lines = $page.Content.Split('') | select -skip 1
+$lines -replace ('\n','') -replace ('.*', '') | % { Write-Host "`"$_`", "}
\ No newline at end of file
diff --git a/vnext/ReactUWP/ReactUWP.vcxproj b/vnext/ReactUWP/ReactUWP.vcxproj
index 03c65e65794..b1882e5948e 100644
--- a/vnext/ReactUWP/ReactUWP.vcxproj
+++ b/vnext/ReactUWP/ReactUWP.vcxproj
@@ -119,7 +119,8 @@
$(ReactNativeWindowsDir)Shared;
$(ReactNativeWindowsDir)stubs;
$(YogaDir);
- %(AdditionalIncludeDirectories)
+ %(AdditionalIncludeDirectories);
+ $(ReactNativeWindowsDir)Microsoft.ReactNative;
$(ChakraCoreInclude);$(ChakraCoreDebugInclude);%(AdditionalIncludeDirectories)
/await %(AdditionalOptions)
@@ -280,6 +281,7 @@
+
diff --git a/vnext/ReactUWP/ReactUWP.vcxproj.filters b/vnext/ReactUWP/ReactUWP.vcxproj.filters
index 72f9ca1a9bc..30f2d7c7f54 100644
--- a/vnext/ReactUWP/ReactUWP.vcxproj.filters
+++ b/vnext/ReactUWP/ReactUWP.vcxproj.filters
@@ -323,6 +323,7 @@
Views
+
diff --git a/vnext/ReactUWP/TestHookMock.cpp b/vnext/ReactUWP/TestHookMock.cpp
new file mode 100644
index 00000000000..7a5af1951d7
--- /dev/null
+++ b/vnext/ReactUWP/TestHookMock.cpp
@@ -0,0 +1,7 @@
+#include "TestHook.h"
+
+void TestHook::NotifyUnimplementedProperty(
+ const std::string &,
+ const std::string &,
+ const std::string &,
+ const folly::dynamic &) {}
diff --git a/vnext/ReactUWP/Views/ViewManagerBase.cpp b/vnext/ReactUWP/Views/ViewManagerBase.cpp
index 9723ceca252..239be0a7da4 100644
--- a/vnext/ReactUWP/Views/ViewManagerBase.cpp
+++ b/vnext/ReactUWP/Views/ViewManagerBase.cpp
@@ -13,6 +13,7 @@
#include
#include
+#include
#include
using namespace folly;
@@ -275,43 +276,6 @@ void ViewManagerBase::NotifyUnimplementedProperty(
#endif // DEBUG
}
-#ifdef DEBUG
-
-void ViewManagerBase::TestHook::NotifyUnimplementedProperty(
- const std::string &viewManager,
- const std::string &reactClassName,
- const std::string &propertyName,
- const folly::dynamic &propertyValue) {
- std::string value;
- size_t size{};
- try {
- if (propertyValue.isObject()) {
- value = "[Object]";
- } else if (propertyValue.isNull()) {
- value = "[Null]";
- } else if (propertyValue.isArray()) {
- size = propertyValue.size();
- value = "[Array]";
- } else {
- value = propertyValue.asString();
- }
- } catch (const TypeError &e) {
- value = e.what();
- }
-
- cdebug << "[UnimplementedProperty] ViewManager = " << viewManager << " elementClass = " << reactClassName
- << " propertyName = " << propertyName << " value = " << value;
-
- if (size != 0) {
- cdebug << " (" << size << " elems)";
- }
-
- cdebug << std::endl;
- // DebugBreak();
-}
-
-#endif // DEBUG
-
void ViewManagerBase::SetLayoutProps(
ShadowNodeBase &nodeToUpdate,
const XamlView &viewToUpdate,
diff --git a/vnext/include/ReactUWP/Views/ViewManagerBase.h b/vnext/include/ReactUWP/Views/ViewManagerBase.h
index ea959424f1c..fab7fad114e 100644
--- a/vnext/include/ReactUWP/Views/ViewManagerBase.h
+++ b/vnext/include/ReactUWP/Views/ViewManagerBase.h
@@ -92,15 +92,7 @@ class REACTWINDOWS_EXPORT ViewManagerBase : public facebook::react::IViewManager
ShadowNodeBase *nodeToUpdate,
const std::string &propertyName,
const folly::dynamic &value);
-#ifdef DEBUG
- struct TestHook {
- static void NotifyUnimplementedProperty(
- const std::string &viewManager,
- const std::string &reactClassName,
- const std::string &propertyName,
- const folly::dynamic &propertyValue);
- };
-#endif
+
protected:
std::weak_ptr m_wkReactInstance;
};