Compare commits

...
Author SHA1 Message Date
Nicola Corti ad5e321d39 Fix eslint warnings in react-native 2024-11-29 12:05:05 +00:00
Andrew Datsenko 5ff59b448b Add defaults to ParagraphAttributes::getDebugProps (#47986)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47986

Changelog: [Internal]

Reviewed By: NickGerleman

Differential Revision: D66542033

fbshipit-source-id: d1f3d1776138d076636765262e27ae8e5e7342c5
2024-11-28 12:07:56 -08:00
Andrew Datsenko de30f408e5 Add defaults to TextAttributes::getDebugProps (#47985)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47985

Changelog: [Internal]

Reviewed By: NickGerleman

Differential Revision: D66542032

fbshipit-source-id: ccecd660f00d3d32909a57534897ba110d53d7b3
2024-11-28 12:07:56 -08:00
Andrew Datsenko 212a743fdf Add float comparison to debugStringConvertilbeUtils (#47984)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47984

Changelog: [Internal]

Reviewed By: NickGerleman

Differential Revision: D66541322

fbshipit-source-id: 1adb52de5c9b0321e328532c4394d8067ffce3d8
2024-11-28 12:07:56 -08:00
Andrew Datsenko b27bd00a38 add jest-diff to dependencies (#47990)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47990

Changelog:
[General][Added] - add `jest-diff v29.7.0` to devDependencies

Reviewed By: NickGerleman

Differential Revision: D66541001

fbshipit-source-id: 01c59a936b66f85ce034b59c7928df3c3f8c2a01
2024-11-28 10:04:46 -08:00
lihaitao 2aa79979d3 fix:setColorScheme exception when activity recreate (#47955)
Summary:
solve the exception  on android when `Appearance.setColorScheme` and activity recreate()
Fixes https://github.com/facebook/react-native/issues/47954

## Changelog:

[Android][Fixed] setColorScheme should be called on the UI thread

Pull Request resolved: https://github.com/facebook/react-native/pull/47955

Reviewed By: cortinico

Differential Revision: D66573373

Pulled By: javache

fbshipit-source-id: 97808e163e1c53bb94f4be7269d9cb9e212f2e95
2024-11-28 09:37:07 -08:00
Alex Hunt 2fcf7b1f49 Allow fuseboxClientType_ detection from ReactNativeApplication.enable method (#47962)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47962

Updates `HostAgent` to respond equivalently if either `FuseboxClient.setClientMetadata` (outgoing) or `ReactNativeApplication.enable` (incoming) are sent by the CDP frontend.

This is a partial migration, to be followed by removing the `FuseboxClient.setClientMetadata` method later.

Changelog: [Internal]

Reviewed By: robhogan

Differential Revision: D66501027

fbshipit-source-id: 1ff669c24667f51d240311e75f95747efe577e2d
2024-11-28 09:26:03 -08:00
Rubén Norte 7ccc5934d0 Implement symbolication of error stack traces (#48006)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/48006

Changelog: [internal]

This implements symbolication of error stack traces in Fantom tests. We just needed to ask Metro to generate source maps and use the `source-map` package to process the stack traces that we get back from the runtime.

Reviewed By: sammy-SC

Differential Revision: D66577818

fbshipit-source-id: 672c66c246ad8646646d5ed31cabca39eb4f7aca
2024-11-28 07:59:26 -08:00
Pieter De Baets bc9e4db9e9 Demonstrate bug in differentiator where reparented nodes reference non-existent nodes (#48002)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/48002

Demonstrates the issue identified in https://github.com/facebook/react-native/issues/47960 and a crash we've been seeing internally around `getViewState` referencing a view that does not exist.

When reparenting unflattened nodes, Differentiator may emit an `update` with a `parentShadowView` that does not exist on the native side yet, thereby crashing Android.

Landing the test-case first (with some test cleanup), so the diff for the actual fix is clearer.

Changelog: [Internal]

Reviewed By: lenaic

Differential Revision: D66557919

fbshipit-source-id: 5428c32e5f0200a8e98568cabeedb0c61aafbe23
2024-11-28 06:06:59 -08:00
13 changed files with 351 additions and 234 deletions
+40
View File
@@ -0,0 +1,40 @@
/**
* (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary.
*
* @flow strict
* @format
* @oncall react_native
*/
declare module 'jest-diff' {
import type {CompareKeys} from 'pretty-format';
declare export type DiffOptionsColor = (arg: string) => string; // subset of Chalk type
declare export type DiffOptions = {
aAnnotation?: string,
aColor?: DiffOptionsColor,
aIndicator?: string,
bAnnotation?: string,
bColor?: DiffOptionsColor,
bIndicator?: string,
changeColor?: DiffOptionsColor,
changeLineTrailingSpaceColor?: DiffOptionsColor,
commonColor?: DiffOptionsColor,
commonIndicator?: string,
commonLineTrailingSpaceColor?: DiffOptionsColor,
contextLines?: number,
emptyFirstOrLastLinePlaceholder?: string,
expand?: boolean,
includeChangeCounts?: boolean,
omitAnnotationLines?: boolean,
patchColor?: DiffOptionsColor,
compareKeys?: CompareKeys,
};
declare export function diff(
a: mixed,
b: mixed,
options?: DiffOptions,
): string | null;
}
+4 -1
View File
@@ -19,7 +19,6 @@ declare type Colors = {
tag: {close: string, open: string},
value: {close: string, open: string},
};
declare type CompareKeys = ((a: string, b: string) => number) | null | void;
declare type PrettyFormatPlugin =
| {
@@ -38,6 +37,10 @@ declare type PrettyFormatPlugin =
};
declare module 'pretty-format' {
declare export type CompareKeys =
| ((a: string, b: string) => number)
| null
| void;
declare export function format(
value: mixed,
options?: ?{
+42 -1
View File
@@ -21,6 +21,8 @@ import Metro from 'metro';
import nullthrows from 'nullthrows';
import os from 'os';
import path from 'path';
// $FlowExpectedError[untyped-import]
import {SourceMapConsumer} from 'source-map';
const BUILD_OUTPUT_PATH = path.resolve(__dirname, '..', 'build');
@@ -130,6 +132,35 @@ function generateBytecodeBundle({
}
}
function symbolicateStackTrace(
sourceMapPath: string,
stackTrace: string,
): string {
const sourceMapData = JSON.parse(fs.readFileSync(sourceMapPath, 'utf8'));
const consumer = new SourceMapConsumer(sourceMapData);
return stackTrace
.split('\n')
.map(line => {
const match = line.match(/at (.*) \((.*):(\d+):(\d+)\)/);
if (match) {
const functionName = match[1];
// const fileName = match[2];
const lineNumber = parseInt(match[3], 10);
const columnNumber = parseInt(match[4], 10);
// Get the original position
const originalPosition = consumer.originalPositionFor({
line: lineNumber,
column: columnNumber,
});
return `at ${originalPosition.name ?? functionName} (${originalPosition.source}:${originalPosition.line}:${originalPosition.column})`;
} else {
return line;
}
})
.join('\n');
}
module.exports = async function runTest(
globalConfig: {...},
config: {...},
@@ -163,12 +194,19 @@ module.exports = async function runTest(
fs.mkdirSync(path.dirname(entrypointPath), {recursive: true});
fs.writeFileSync(entrypointPath, entrypointContents, 'utf8');
const sourceMapPath = path.join(
path.dirname(testJSBundlePath),
path.basename(testJSBundlePath, '.js') + '.map',
);
await Metro.runBuild(metroConfig, {
entry: entrypointPath,
out: testJSBundlePath,
platform: 'android',
minify: isOptimizedMode,
dev: !isOptimizedMode,
sourceMap: true,
sourceMapUrl: sourceMapPath,
});
if (isOptimizedMode) {
@@ -232,7 +270,7 @@ module.exports = async function runTest(
const testResultError = rnTesterParsedOutput.testResult.error;
if (testResultError) {
const error = new Error(testResultError.message);
error.stack = testResultError.stack;
error.stack = symbolicateStackTrace(sourceMapPath, testResultError.stack);
throw error;
}
@@ -248,6 +286,9 @@ module.exports = async function runTest(
failureDetails: [] as Array<string>,
testFilePath: testPath,
...testResult,
failureMessages: testResult.failureMessages.map(maybeStackTrace =>
symbolicateStackTrace(sourceMapPath, maybeStackTrace),
),
})) ?? [];
return {
+1
View File
@@ -83,6 +83,7 @@
"hermes-transform": "0.25.1",
"inquirer": "^7.1.0",
"jest": "^29.6.3",
"jest-diff": "^29.7.0",
"jest-junit": "^10.0.0",
"jscodeshift": "^0.14.0",
"metro-babel-register": "^0.81.0",
@@ -13,6 +13,7 @@ import androidx.appcompat.app.AppCompatDelegate
import com.facebook.fbreact.specs.NativeAppearanceSpec
import com.facebook.react.bridge.Arguments
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.UiThreadUtil
import com.facebook.react.module.annotations.ReactModule
/** Module that exposes the user's preferred color scheme. */
@@ -58,11 +59,13 @@ constructor(
}
public override fun setColorScheme(style: String) {
when (style) {
"dark" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
"light" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
"unspecified" ->
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
UiThreadUtil.runOnUiThread {
when (style) {
"dark" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
"light" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
"unspecified" ->
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
}
}
}
@@ -136,6 +136,11 @@ void HostAgent::handleRequest(const cdp::PreparsedRequest& req) {
isFinishedHandlingRequest = true;
} else if (req.method == "ReactNativeApplication.enable") {
sessionState_.isReactNativeApplicationDomainEnabled = true;
fuseboxClientType_ = FuseboxClientType::Fusebox;
if (sessionState_.isLogDomainEnabled) {
sendFuseboxNotice();
}
frontendChannel_(cdp::jsonNotification(
"ReactNativeApplication.metadataUpdated",
@@ -187,11 +192,16 @@ HostAgent::~HostAgent() {
}
void HostAgent::sendFuseboxNotice() {
if (fuseboxNoticeLogged_) {
return;
}
static constexpr auto kFuseboxNotice =
ANSI_COLOR_BG_YELLOW "Welcome to " ANSI_WEIGHT_BOLD
"React Native DevTools" ANSI_WEIGHT_RESET ""sv;
sendInfoLogEntry(kFuseboxNotice);
fuseboxNoticeLogged_ = true;
}
void HostAgent::sendNonFuseboxNotice() {
@@ -102,6 +102,7 @@ class HostAgent final {
const HostTargetMetadata hostMetadata_;
std::shared_ptr<InstanceAgent> instanceAgent_;
FuseboxClientType fuseboxClientType_{FuseboxClientType::Unknown};
bool fuseboxNoticeLogged_{false};
bool isPausedInDebuggerOverlayVisible_{false};
/**
@@ -41,16 +41,38 @@ bool ParagraphAttributes::operator!=(const ParagraphAttributes& rhs) const {
#if RN_DEBUG_STRING_CONVERTIBLE
SharedDebugStringConvertibleList ParagraphAttributes::getDebugProps() const {
ParagraphAttributes paragraphAttributes{};
return {
debugStringConvertibleItem("maximumNumberOfLines", maximumNumberOfLines),
debugStringConvertibleItem("ellipsizeMode", ellipsizeMode),
debugStringConvertibleItem("textBreakStrategy", textBreakStrategy),
debugStringConvertibleItem("adjustsFontSizeToFit", adjustsFontSizeToFit),
debugStringConvertibleItem("minimumFontSize", minimumFontSize),
debugStringConvertibleItem("maximumFontSize", maximumFontSize),
debugStringConvertibleItem("includeFontPadding", includeFontPadding),
debugStringConvertibleItem(
"android_hyphenationFrequency", android_hyphenationFrequency)};
"maximumNumberOfLines",
maximumNumberOfLines,
paragraphAttributes.maximumNumberOfLines),
debugStringConvertibleItem(
"ellipsizeMode", ellipsizeMode, paragraphAttributes.ellipsizeMode),
debugStringConvertibleItem(
"textBreakStrategy",
textBreakStrategy,
paragraphAttributes.textBreakStrategy),
debugStringConvertibleItem(
"adjustsFontSizeToFit",
adjustsFontSizeToFit,
paragraphAttributes.adjustsFontSizeToFit),
debugStringConvertibleItem(
"minimumFontSize",
minimumFontSize,
paragraphAttributes.minimumFontSize),
debugStringConvertibleItem(
"maximumFontSize",
maximumFontSize,
paragraphAttributes.maximumFontSize),
debugStringConvertibleItem(
"includeFontPadding",
includeFontPadding,
paragraphAttributes.includeFontPadding),
debugStringConvertibleItem(
"android_hyphenationFrequency",
android_hyphenationFrequency,
paragraphAttributes.android_hyphenationFrequency)};
}
#endif
@@ -197,49 +197,97 @@ TextAttributes TextAttributes::defaultTextAttributes() {
#if RN_DEBUG_STRING_CONVERTIBLE
SharedDebugStringConvertibleList TextAttributes::getDebugProps() const {
const auto& textAttributes = TextAttributes::defaultTextAttributes();
return {
// Color
debugStringConvertibleItem("backgroundColor", backgroundColor),
debugStringConvertibleItem("foregroundColor", foregroundColor),
debugStringConvertibleItem("opacity", opacity),
debugStringConvertibleItem(
"backgroundColor", backgroundColor, textAttributes.backgroundColor),
debugStringConvertibleItem(
"foregroundColor", foregroundColor, textAttributes.foregroundColor),
debugStringConvertibleItem("opacity", opacity, textAttributes.opacity),
// Font
debugStringConvertibleItem("fontFamily", fontFamily),
debugStringConvertibleItem("fontSize", fontSize),
debugStringConvertibleItem("fontSizeMultiplier", fontSizeMultiplier),
debugStringConvertibleItem("fontWeight", fontWeight),
debugStringConvertibleItem("fontStyle", fontStyle),
debugStringConvertibleItem("fontVariant", fontVariant),
debugStringConvertibleItem("allowFontScaling", allowFontScaling),
debugStringConvertibleItem("dynamicTypeRamp", dynamicTypeRamp),
debugStringConvertibleItem("letterSpacing", letterSpacing),
debugStringConvertibleItem(
"fontFamily", fontFamily, textAttributes.fontFamily),
debugStringConvertibleItem("fontSize", fontSize, textAttributes.fontSize),
debugStringConvertibleItem(
"fontSizeMultiplier",
fontSizeMultiplier,
textAttributes.fontSizeMultiplier),
debugStringConvertibleItem(
"fontWeight", fontWeight, textAttributes.fontWeight),
debugStringConvertibleItem(
"fontStyle", fontStyle, textAttributes.fontStyle),
debugStringConvertibleItem(
"fontVariant", fontVariant, textAttributes.fontVariant),
debugStringConvertibleItem(
"allowFontScaling",
allowFontScaling,
textAttributes.allowFontScaling),
debugStringConvertibleItem(
"dynamicTypeRamp", dynamicTypeRamp, textAttributes.dynamicTypeRamp),
debugStringConvertibleItem(
"letterSpacing", letterSpacing, textAttributes.letterSpacing),
// Paragraph Styles
debugStringConvertibleItem("lineHeight", lineHeight),
debugStringConvertibleItem("alignment", alignment),
debugStringConvertibleItem("baseWritingDirection", baseWritingDirection),
debugStringConvertibleItem("lineBreakStrategyIOS", lineBreakStrategy),
debugStringConvertibleItem("lineBreakModeIOS", lineBreakMode),
debugStringConvertibleItem(
"lineHeight", lineHeight, textAttributes.lineHeight),
debugStringConvertibleItem(
"alignment", alignment, textAttributes.alignment),
debugStringConvertibleItem(
"baseWritingDirection",
baseWritingDirection,
textAttributes.baseWritingDirection),
debugStringConvertibleItem(
"lineBreakStrategyIOS",
lineBreakStrategy,
textAttributes.lineBreakStrategy),
debugStringConvertibleItem(
"lineBreakModeIOS", lineBreakMode, textAttributes.lineBreakMode),
// Decoration
debugStringConvertibleItem("textDecorationColor", textDecorationColor),
debugStringConvertibleItem(
"textDecorationLineType", textDecorationLineType),
debugStringConvertibleItem("textDecorationStyle", textDecorationStyle),
"textDecorationColor",
textDecorationColor,
textAttributes.textDecorationColor),
debugStringConvertibleItem(
"textDecorationLineType",
textDecorationLineType,
textAttributes.textDecorationLineType),
debugStringConvertibleItem(
"textDecorationStyle",
textDecorationStyle,
textAttributes.textDecorationStyle),
// Shadow
debugStringConvertibleItem("textShadowOffset", textShadowOffset),
debugStringConvertibleItem("textShadowRadius", textShadowRadius),
debugStringConvertibleItem("textShadowColor", textShadowColor),
debugStringConvertibleItem(
"textShadowOffset",
textShadowOffset,
textAttributes.textShadowOffset),
debugStringConvertibleItem(
"textShadowRadius",
textShadowRadius,
textAttributes.textShadowRadius),
debugStringConvertibleItem(
"textShadowColor", textShadowColor, textAttributes.textShadowColor),
// Special
debugStringConvertibleItem("isHighlighted", isHighlighted),
debugStringConvertibleItem("isPressable", isPressable),
debugStringConvertibleItem("layoutDirection", layoutDirection),
debugStringConvertibleItem("accessibilityRole", accessibilityRole),
debugStringConvertibleItem("role", role),
debugStringConvertibleItem(
"isHighlighted", isHighlighted, textAttributes.isHighlighted),
debugStringConvertibleItem(
"isPressable", isPressable, textAttributes.isPressable),
debugStringConvertibleItem(
"layoutDirection", layoutDirection, textAttributes.layoutDirection),
debugStringConvertibleItem(
"accessibilityRole",
accessibilityRole,
textAttributes.accessibilityRole),
debugStringConvertibleItem("role", role, textAttributes.role),
debugStringConvertibleItem("textAlignVertical", textAlignVertical),
debugStringConvertibleItem(
"textAlignVertical",
textAlignVertical,
textAttributes.textAlignVertical),
};
}
#endif
@@ -15,14 +15,29 @@
#include <react/renderer/debug/DebugStringConvertible.h>
#include <react/renderer/debug/DebugStringConvertibleItem.h>
#include <react/utils/FloatComparison.h>
namespace facebook::react {
#if RN_DEBUG_STRING_CONVERTIBLE
inline SharedDebugStringConvertible debugStringConvertibleItem(
const std::string& name,
float value,
float defaultValue = {}) {
if (floatEquality(value, defaultValue)) {
return nullptr;
}
return std::make_shared<DebugStringConvertibleItem>(
name, facebook::react::toString(value));
}
template <typename T>
inline SharedDebugStringConvertible
debugStringConvertibleItem(std::string name, T value, T defaultValue = {}) {
inline SharedDebugStringConvertible debugStringConvertibleItem(
const std::string& name,
T value,
T defaultValue = {}) {
if (value == defaultValue) {
return nullptr;
}
@@ -33,7 +48,7 @@ debugStringConvertibleItem(std::string name, T value, T defaultValue = {}) {
template <typename T>
inline SharedDebugStringConvertible debugStringConvertibleItem(
std::string name,
const std::string& name,
std::optional<T> value,
T defaultValue = {}) {
if (!value.has_value()) {
@@ -54,7 +69,7 @@ inline SharedDebugStringConvertibleList operator+(
}
inline SharedDebugStringConvertible debugStringConvertibleItem(
std::string name,
const std::string& name,
DebugStringConvertible value,
std::string defaultValue) {
return debugStringConvertibleItem(
@@ -45,17 +45,22 @@ static SharedViewProps nonFlattenedDefaultProps(
static ShadowNode::Shared makeNode(
const ComponentDescriptor& componentDescriptor,
int tag,
const ShadowNode::ListOfShared& children,
std::shared_ptr<ShadowNode::ListOfShared> children,
bool flattened = false) {
auto props = flattened ? generateDefaultProps(componentDescriptor)
: nonFlattenedDefaultProps(componentDescriptor);
return componentDescriptor.createShadowNode(
ShadowNodeFragment{
props, std::make_shared<ShadowNode::ListOfShared>(children)},
ShadowNodeFragment{std::move(props), std::move(children)},
componentDescriptor.createFamily({tag, SurfaceId(1), nullptr}));
}
static std::shared_ptr<ShadowNode::ListOfShared> listOfChildren(
std::initializer_list<ShadowNode::Shared> list) {
return std::make_shared<ShadowNode::ListOfShared>(
ShadowNode::ListOfShared{list});
}
/**
* Test reordering of views with the same parent:
*
@@ -117,25 +122,20 @@ TEST(MountingTest, testReorderingInstructionGeneration) {
auto shadowNodeV1 = viewComponentDescriptor.createShadowNode(
ShadowNodeFragment{
generateDefaultProps(viewComponentDescriptor),
std::make_shared<ShadowNode::ListOfShared>(
ShadowNode::ListOfShared{childB, childC, childD})},
listOfChildren({childB, childC, childD})},
family);
auto shadowNodeV2 = shadowNodeV1->clone(ShadowNodeFragment{
generateDefaultProps(viewComponentDescriptor),
std::make_shared<ShadowNode::ListOfShared>(
ShadowNode::ListOfShared{childA, childB, childC, childD})});
listOfChildren({childA, childB, childC, childD})});
auto shadowNodeV3 = shadowNodeV2->clone(ShadowNodeFragment{
generateDefaultProps(viewComponentDescriptor),
std::make_shared<ShadowNode::ListOfShared>(
ShadowNode::ListOfShared{childB, childC, childD})});
listOfChildren({childB, childC, childD})});
auto shadowNodeV4 = shadowNodeV3->clone(ShadowNodeFragment{
generateDefaultProps(viewComponentDescriptor),
std::make_shared<ShadowNode::ListOfShared>(
ShadowNode::ListOfShared{childB, childD, childE})});
listOfChildren({childB, childD, childE})});
auto shadowNodeV5 = shadowNodeV4->clone(ShadowNodeFragment{
generateDefaultProps(viewComponentDescriptor),
std::make_shared<ShadowNode::ListOfShared>(
ShadowNode::ListOfShared{childB, childA, childE, childC})});
listOfChildren({childB, childA, childE, childC})});
auto shadowNodeV6 = shadowNodeV5->clone(ShadowNodeFragment{
generateDefaultProps(viewComponentDescriptor),
std::make_shared<ShadowNode::ListOfShared>(ShadowNode::ListOfShared{
@@ -157,38 +157,31 @@ TEST(MountingTest, testReorderingInstructionGeneration) {
auto rootNodeV1 = std::static_pointer_cast<const RootShadowNode>(
emptyRootNode->ShadowNode::clone(ShadowNodeFragment{
ShadowNodeFragment::propsPlaceholder(),
std::make_shared<ShadowNode::ListOfShared>(
ShadowNode::ListOfShared{shadowNodeV1})}));
listOfChildren({shadowNodeV1})}));
auto rootNodeV2 = std::static_pointer_cast<const RootShadowNode>(
rootNodeV1->ShadowNode::clone(ShadowNodeFragment{
ShadowNodeFragment::propsPlaceholder(),
std::make_shared<ShadowNode::ListOfShared>(
ShadowNode::ListOfShared{shadowNodeV2})}));
listOfChildren({shadowNodeV2})}));
auto rootNodeV3 = std::static_pointer_cast<const RootShadowNode>(
rootNodeV2->ShadowNode::clone(ShadowNodeFragment{
ShadowNodeFragment::propsPlaceholder(),
std::make_shared<ShadowNode::ListOfShared>(
ShadowNode::ListOfShared{shadowNodeV3})}));
listOfChildren({shadowNodeV3})}));
auto rootNodeV4 = std::static_pointer_cast<const RootShadowNode>(
rootNodeV3->ShadowNode::clone(ShadowNodeFragment{
ShadowNodeFragment::propsPlaceholder(),
std::make_shared<ShadowNode::ListOfShared>(
ShadowNode::ListOfShared{shadowNodeV4})}));
listOfChildren({shadowNodeV4})}));
auto rootNodeV5 = std::static_pointer_cast<const RootShadowNode>(
rootNodeV4->ShadowNode::clone(ShadowNodeFragment{
ShadowNodeFragment::propsPlaceholder(),
std::make_shared<ShadowNode::ListOfShared>(
ShadowNode::ListOfShared{shadowNodeV5})}));
listOfChildren({shadowNodeV5})}));
auto rootNodeV6 = std::static_pointer_cast<const RootShadowNode>(
rootNodeV5->ShadowNode::clone(ShadowNodeFragment{
ShadowNodeFragment::propsPlaceholder(),
std::make_shared<ShadowNode::ListOfShared>(
ShadowNode::ListOfShared{shadowNodeV6})}));
listOfChildren({shadowNodeV6})}));
auto rootNodeV7 = std::static_pointer_cast<const RootShadowNode>(
rootNodeV6->ShadowNode::clone(ShadowNodeFragment{
ShadowNodeFragment::propsPlaceholder(),
std::make_shared<ShadowNode::ListOfShared>(
ShadowNode::ListOfShared{shadowNodeV7})}));
listOfChildren({shadowNodeV7})}));
// Layout
std::vector<const LayoutableShadowNode*> affectedLayoutableNodesV1{};
@@ -289,7 +282,6 @@ TEST(MountingTest, testReorderingInstructionGeneration) {
// Calculating mutations.
auto mutations3 = calculateShadowViewMutations(*rootNodeV3, *rootNodeV4);
LOG(ERROR) << "Num mutations IN OLD TEST mutations3: " << mutations3.size();
// The order and exact mutation instructions here may change at any time.
// This test just ensures that any changes are intentional.
@@ -425,172 +417,107 @@ TEST(MountingTest, testViewReparentingInstructionGeneration) {
auto family =
viewComponentDescriptor.createFamily({10, SurfaceId(1), nullptr});
auto reparentedViewA = makeNode(
viewComponentDescriptor,
1000,
ShadowNode::ListOfShared{
childC->clone({}), childA->clone({}), childB->clone({})});
auto reparentedViewA_ = makeNode(
viewComponentDescriptor, 1000, listOfChildren({childC, childA, childB}));
auto reparentedViewA = reparentedViewA_->clone(
ShadowNodeFragment{nonFlattenedDefaultProps(viewComponentDescriptor)});
auto reparentedViewB = makeNode(
viewComponentDescriptor,
2000,
ShadowNode::ListOfShared{
childF->clone({}), childE->clone({}), childD->clone({})});
viewComponentDescriptor, 2000, listOfChildren({childF, childE, childD}));
// Root -> G* -> H -> I -> J -> A* [nodes with * are _not_ flattened]
auto shadowNodeV1 = viewComponentDescriptor.createShadowNode(
ShadowNodeFragment{
generateDefaultProps(viewComponentDescriptor),
std::make_shared<ShadowNode::ListOfShared>(
ShadowNode::ListOfShared{childG->clone(ShadowNodeFragment{
nonFlattenedDefaultProps(viewComponentDescriptor),
std::make_shared<ShadowNode::ListOfShared>(
ShadowNode::ListOfShared{childH->clone(ShadowNodeFragment{
listOfChildren({childG->clone(ShadowNodeFragment{
nonFlattenedDefaultProps(viewComponentDescriptor),
listOfChildren({childH->clone(ShadowNodeFragment{
generateDefaultProps(viewComponentDescriptor),
listOfChildren({childI->clone(ShadowNodeFragment{
generateDefaultProps(viewComponentDescriptor),
listOfChildren({childJ->clone(ShadowNodeFragment{
generateDefaultProps(viewComponentDescriptor),
std::make_shared<ShadowNode::ListOfShared>(
ShadowNode::ListOfShared{
childI->clone(ShadowNodeFragment{
generateDefaultProps(
viewComponentDescriptor),
std::make_shared<
ShadowNode::ListOfShared>(
ShadowNode::ListOfShared{
childJ->clone(ShadowNodeFragment{
generateDefaultProps(
viewComponentDescriptor),
std::make_shared<
ShadowNode::ListOfShared>(
ShadowNode::ListOfShared{
reparentedViewA->clone(
{})})})})})})})})})})},
listOfChildren({reparentedViewA_})})})})})})})})})},
family);
// Root -> G* -> H* -> I -> J -> A* [nodes with * are _not_ flattened]
// Force an update with A with new props
auto shadowNodeV2 = shadowNodeV1->clone(ShadowNodeFragment{
generateDefaultProps(viewComponentDescriptor),
std::make_shared<ShadowNode::ListOfShared>(
ShadowNode::ListOfShared{childG->clone(ShadowNodeFragment{
listOfChildren({childG->clone(ShadowNodeFragment{
nonFlattenedDefaultProps(viewComponentDescriptor),
listOfChildren({childH->clone(ShadowNodeFragment{
nonFlattenedDefaultProps(viewComponentDescriptor),
std::make_shared<ShadowNode::ListOfShared>(
ShadowNode::ListOfShared{childH->clone(ShadowNodeFragment{
nonFlattenedDefaultProps(viewComponentDescriptor),
std::make_shared<
ShadowNode::ListOfShared>(ShadowNode::ListOfShared{
childI->clone(ShadowNodeFragment{
generateDefaultProps(viewComponentDescriptor),
std::make_shared<ShadowNode::ListOfShared>(
ShadowNode::ListOfShared{
childJ->clone(ShadowNodeFragment{
generateDefaultProps(
viewComponentDescriptor),
std::make_shared<
ShadowNode::ListOfShared>(
ShadowNode::ListOfShared{
reparentedViewA->clone(
{})})})})})})})})})})});
listOfChildren({childI->clone(ShadowNodeFragment{
generateDefaultProps(viewComponentDescriptor),
listOfChildren({childJ->clone(ShadowNodeFragment{
generateDefaultProps(viewComponentDescriptor),
listOfChildren({reparentedViewA})})})})})})})})})});
// Root -> G* -> H -> I -> J -> A* [nodes with * are _not_ flattened]
auto shadowNodeV3 = shadowNodeV2->clone(ShadowNodeFragment{
generateDefaultProps(viewComponentDescriptor),
std::make_shared<ShadowNode::ListOfShared>(
ShadowNode::ListOfShared{childG->clone(ShadowNodeFragment{
nonFlattenedDefaultProps(viewComponentDescriptor),
std::make_shared<ShadowNode::ListOfShared>(
ShadowNode::ListOfShared{childH->clone(ShadowNodeFragment{
listOfChildren({childG->clone(ShadowNodeFragment{
nonFlattenedDefaultProps(viewComponentDescriptor),
listOfChildren({childH->clone(ShadowNodeFragment{
generateDefaultProps(viewComponentDescriptor),
listOfChildren({childI->clone(ShadowNodeFragment{
generateDefaultProps(viewComponentDescriptor),
listOfChildren({childJ->clone(ShadowNodeFragment{
generateDefaultProps(viewComponentDescriptor),
std::make_shared<
ShadowNode::ListOfShared>(ShadowNode::ListOfShared{
childI->clone(ShadowNodeFragment{
generateDefaultProps(viewComponentDescriptor),
std::make_shared<ShadowNode::ListOfShared>(
ShadowNode::ListOfShared{
childJ->clone(ShadowNodeFragment{
generateDefaultProps(
viewComponentDescriptor),
std::make_shared<
ShadowNode::ListOfShared>(
ShadowNode::ListOfShared{
reparentedViewA->clone(
{})})})})})})})})})})});
listOfChildren({reparentedViewA})})})})})})})})})});
// The view is reparented 1 level down with a different sibling
// Root -> G* -> H* -> I* -> J -> [B*, A*] [nodes with * are _not_ flattened]
auto shadowNodeV4 = shadowNodeV3->clone(ShadowNodeFragment{
generateDefaultProps(viewComponentDescriptor),
std::make_shared<ShadowNode::ListOfShared>(
ShadowNode::ListOfShared{childG->clone(ShadowNodeFragment{
listOfChildren({childG->clone(ShadowNodeFragment{
nonFlattenedDefaultProps(viewComponentDescriptor),
listOfChildren({childH->clone(ShadowNodeFragment{
nonFlattenedDefaultProps(viewComponentDescriptor),
std::make_shared<ShadowNode::ListOfShared>(
ShadowNode::ListOfShared{childH->clone(ShadowNodeFragment{
nonFlattenedDefaultProps(viewComponentDescriptor),
std::make_shared<
ShadowNode::ListOfShared>(ShadowNode::ListOfShared{
childI->clone(ShadowNodeFragment{
nonFlattenedDefaultProps(viewComponentDescriptor),
std::make_shared<ShadowNode::ListOfShared>(
ShadowNode::ListOfShared{
childJ->clone(ShadowNodeFragment{
generateDefaultProps(
viewComponentDescriptor),
std::make_shared<
ShadowNode::ListOfShared>(
ShadowNode::ListOfShared{
reparentedViewB->clone({}),
reparentedViewA->clone(
{})})})})})})})})})})});
listOfChildren({childI->clone(ShadowNodeFragment{
nonFlattenedDefaultProps(viewComponentDescriptor),
listOfChildren({childJ->clone(ShadowNodeFragment{
generateDefaultProps(viewComponentDescriptor),
listOfChildren(
{reparentedViewB, reparentedViewA})})})})})})})})})});
// The view is reparented 1 level further down with its order with the sibling
// swapped
// Root -> G* -> H* -> I* -> J* -> [A*, B*] [nodes with * are _not_ flattened]
auto shadowNodeV5 = shadowNodeV4->clone(ShadowNodeFragment{
generateDefaultProps(viewComponentDescriptor),
std::make_shared<ShadowNode::ListOfShared>(
ShadowNode::ListOfShared{childG->clone(ShadowNodeFragment{
listOfChildren({childG->clone(ShadowNodeFragment{
nonFlattenedDefaultProps(viewComponentDescriptor),
listOfChildren({childH->clone(ShadowNodeFragment{
nonFlattenedDefaultProps(viewComponentDescriptor),
std::make_shared<ShadowNode::ListOfShared>(
ShadowNode::ListOfShared{childH->clone(ShadowNodeFragment{
listOfChildren({childI->clone(ShadowNodeFragment{
nonFlattenedDefaultProps(viewComponentDescriptor),
listOfChildren({childJ->clone(ShadowNodeFragment{
nonFlattenedDefaultProps(viewComponentDescriptor),
std::make_shared<
ShadowNode::ListOfShared>(ShadowNode::ListOfShared{
childI->clone(ShadowNodeFragment{
nonFlattenedDefaultProps(viewComponentDescriptor),
std::make_shared<ShadowNode::ListOfShared>(
ShadowNode::ListOfShared{
childJ->clone(ShadowNodeFragment{
nonFlattenedDefaultProps(
viewComponentDescriptor),
std::make_shared<
ShadowNode::ListOfShared>(
ShadowNode::ListOfShared{
reparentedViewA->clone({}),
reparentedViewB->clone(
{})})})})})})})})})})});
listOfChildren(
{reparentedViewA, reparentedViewB})})})})})})})})})});
// Injecting a tree into the root node.
auto rootNodeV1 = std::static_pointer_cast<const RootShadowNode>(
emptyRootNode->ShadowNode::clone(ShadowNodeFragment{
ShadowNodeFragment::propsPlaceholder(),
std::make_shared<ShadowNode::ListOfShared>(
ShadowNode::ListOfShared{shadowNodeV1})}));
listOfChildren({shadowNodeV1})}));
auto rootNodeV2 = std::static_pointer_cast<const RootShadowNode>(
rootNodeV1->ShadowNode::clone(ShadowNodeFragment{
ShadowNodeFragment::propsPlaceholder(),
std::make_shared<ShadowNode::ListOfShared>(
ShadowNode::ListOfShared{shadowNodeV2})}));
listOfChildren({shadowNodeV2})}));
auto rootNodeV3 = std::static_pointer_cast<const RootShadowNode>(
rootNodeV2->ShadowNode::clone(ShadowNodeFragment{
ShadowNodeFragment::propsPlaceholder(),
std::make_shared<ShadowNode::ListOfShared>(
ShadowNode::ListOfShared{shadowNodeV3})}));
listOfChildren({shadowNodeV3})}));
auto rootNodeV4 = std::static_pointer_cast<const RootShadowNode>(
rootNodeV3->ShadowNode::clone(ShadowNodeFragment{
ShadowNodeFragment::propsPlaceholder(),
std::make_shared<ShadowNode::ListOfShared>(
ShadowNode::ListOfShared{shadowNodeV4})}));
listOfChildren({shadowNodeV4})}));
auto rootNodeV5 = std::static_pointer_cast<const RootShadowNode>(
rootNodeV4->ShadowNode::clone(ShadowNodeFragment{
ShadowNodeFragment::propsPlaceholder(),
std::make_shared<ShadowNode::ListOfShared>(
ShadowNode::ListOfShared{shadowNodeV5})}));
listOfChildren({shadowNodeV5})}));
// Layout
std::vector<const LayoutableShadowNode*> affectedLayoutableNodesV1{};
@@ -626,33 +553,38 @@ TEST(MountingTest, testViewReparentingInstructionGeneration) {
// Calculating mutations.
auto mutations1 = calculateShadowViewMutations(*rootNodeV1, *rootNodeV2);
EXPECT_EQ(mutations1.size(), 5);
EXPECT_EQ(mutations1.size(), 6);
EXPECT_EQ(mutations1[0].type, ShadowViewMutation::Update);
EXPECT_EQ(mutations1[0].oldChildShadowView.tag, 106);
EXPECT_EQ(mutations1[1].type, ShadowViewMutation::Remove);
EXPECT_EQ(mutations1[1].oldChildShadowView.tag, 1000);
EXPECT_EQ(mutations1[2].type, ShadowViewMutation::Create);
EXPECT_EQ(mutations1[2].newChildShadowView.tag, 107);
EXPECT_EQ(mutations1[3].type, ShadowViewMutation::Insert);
EXPECT_EQ(mutations1[3].newChildShadowView.tag, 107);
EXPECT_EQ(mutations1[0].oldChildShadowView.tag, childG->getTag());
EXPECT_EQ(mutations1[1].type, ShadowViewMutation::Update);
EXPECT_EQ(mutations1[1].oldChildShadowView.tag, reparentedViewA->getTag());
// This is incorrect! ChildH does not exist yet at this point
EXPECT_EQ(mutations1[1].parentShadowView.tag, childH->getTag());
EXPECT_EQ(mutations1[2].type, ShadowViewMutation::Remove);
EXPECT_EQ(mutations1[2].oldChildShadowView.tag, reparentedViewA->getTag());
EXPECT_EQ(mutations1[3].type, ShadowViewMutation::Create);
EXPECT_EQ(mutations1[3].newChildShadowView.tag, childH->getTag());
EXPECT_EQ(mutations1[4].type, ShadowViewMutation::Insert);
EXPECT_EQ(mutations1[4].newChildShadowView.tag, 1000);
EXPECT_EQ(mutations1[4].newChildShadowView.tag, childH->getTag());
EXPECT_EQ(mutations1[5].type, ShadowViewMutation::Insert);
EXPECT_EQ(mutations1[5].newChildShadowView.tag, reparentedViewA->getTag());
auto mutations2 = calculateShadowViewMutations(*rootNodeV2, *rootNodeV3);
EXPECT_EQ(mutations2.size(), 5);
EXPECT_EQ(mutations2[0].type, ShadowViewMutation::Update);
EXPECT_EQ(mutations2[0].oldChildShadowView.tag, 106);
EXPECT_EQ(mutations2[0].oldChildShadowView.tag, childG->getTag());
EXPECT_EQ(mutations2[0].parentShadowView.tag, emptyRootNode->getTag());
EXPECT_EQ(mutations2[1].type, ShadowViewMutation::Remove);
EXPECT_EQ(mutations2[1].oldChildShadowView.tag, 1000);
EXPECT_EQ(mutations2[1].oldChildShadowView.tag, reparentedViewA->getTag());
EXPECT_EQ(mutations2[2].type, ShadowViewMutation::Remove);
EXPECT_EQ(mutations2[2].oldChildShadowView.tag, 107);
EXPECT_EQ(mutations2[2].oldChildShadowView.tag, childH->getTag());
EXPECT_EQ(
mutations2[3].type,
ShadowViewMutation::Delete); // correct, 107 is removed from tree entirely
EXPECT_EQ(mutations2[3].oldChildShadowView.tag, 107);
ShadowViewMutation::Delete); // correct, H is removed from tree entirely
EXPECT_EQ(mutations2[3].oldChildShadowView.tag, childH->getTag());
EXPECT_EQ(mutations2[4].type, ShadowViewMutation::Insert);
EXPECT_EQ(mutations2[4].newChildShadowView.tag, 1000);
EXPECT_EQ(mutations2[4].newChildShadowView.tag, reparentedViewA->getTag());
auto mutations3 = calculateShadowViewMutations(*rootNodeV3, *rootNodeV4);
@@ -661,57 +593,58 @@ TEST(MountingTest, testViewReparentingInstructionGeneration) {
EXPECT_EQ(mutations3.size(), 15);
EXPECT_EQ(mutations3[0].type, ShadowViewMutation::Update);
EXPECT_EQ(mutations3[0].oldChildShadowView.tag, 106);
EXPECT_EQ(mutations3[0].oldChildShadowView.tag, childG->getTag());
EXPECT_EQ(mutations3[0].parentShadowView.tag, emptyRootNode->getTag());
EXPECT_EQ(mutations3[1].type, ShadowViewMutation::Remove);
EXPECT_EQ(mutations3[1].oldChildShadowView.tag, 1000);
EXPECT_EQ(mutations3[1].oldChildShadowView.tag, reparentedViewA->getTag());
EXPECT_EQ(mutations3[2].type, ShadowViewMutation::Create);
EXPECT_EQ(mutations3[2].newChildShadowView.tag, 107);
EXPECT_EQ(mutations3[2].newChildShadowView.tag, childH->getTag());
EXPECT_EQ(mutations3[3].type, ShadowViewMutation::Create);
EXPECT_EQ(mutations3[3].newChildShadowView.tag, 2000);
EXPECT_EQ(mutations3[3].newChildShadowView.tag, reparentedViewB->getTag());
EXPECT_EQ(mutations3[4].type, ShadowViewMutation::Create);
EXPECT_EQ(mutations3[4].newChildShadowView.tag, 108);
EXPECT_EQ(mutations3[4].newChildShadowView.tag, childI->getTag());
EXPECT_EQ(mutations3[5].type, ShadowViewMutation::Create);
EXPECT_EQ(mutations3[5].newChildShadowView.tag, 105);
EXPECT_EQ(mutations3[5].newChildShadowView.tag, childF->getTag());
EXPECT_EQ(mutations3[6].type, ShadowViewMutation::Create);
EXPECT_EQ(mutations3[6].newChildShadowView.tag, 104);
EXPECT_EQ(mutations3[6].newChildShadowView.tag, childE->getTag());
EXPECT_EQ(mutations3[7].type, ShadowViewMutation::Create);
EXPECT_EQ(mutations3[7].newChildShadowView.tag, 103);
EXPECT_EQ(mutations3[7].newChildShadowView.tag, childD->getTag());
EXPECT_EQ(mutations3[8].type, ShadowViewMutation::Insert);
EXPECT_EQ(mutations3[8].newChildShadowView.tag, 105);
EXPECT_EQ(mutations3[8].newChildShadowView.tag, childF->getTag());
EXPECT_EQ(mutations3[9].type, ShadowViewMutation::Insert);
EXPECT_EQ(mutations3[9].newChildShadowView.tag, 104);
EXPECT_EQ(mutations3[9].newChildShadowView.tag, childE->getTag());
EXPECT_EQ(mutations3[10].type, ShadowViewMutation::Insert);
EXPECT_EQ(mutations3[10].newChildShadowView.tag, 103);
EXPECT_EQ(mutations3[10].newChildShadowView.tag, childD->getTag());
EXPECT_EQ(mutations3[11].type, ShadowViewMutation::Insert);
EXPECT_EQ(mutations3[11].newChildShadowView.tag, 107);
EXPECT_EQ(mutations3[11].newChildShadowView.tag, childH->getTag());
EXPECT_EQ(mutations3[12].type, ShadowViewMutation::Insert);
EXPECT_EQ(mutations3[12].newChildShadowView.tag, 108);
EXPECT_EQ(mutations3[12].newChildShadowView.tag, childI->getTag());
EXPECT_EQ(mutations3[13].type, ShadowViewMutation::Insert);
EXPECT_EQ(mutations3[13].newChildShadowView.tag, 2000);
EXPECT_EQ(mutations3[13].newChildShadowView.tag, reparentedViewB->getTag());
EXPECT_EQ(mutations3[14].type, ShadowViewMutation::Insert);
EXPECT_EQ(mutations3[14].newChildShadowView.tag, 1000);
EXPECT_EQ(mutations3[14].newChildShadowView.tag, reparentedViewA->getTag());
auto mutations4 = calculateShadowViewMutations(*rootNodeV4, *rootNodeV5);
EXPECT_EQ(mutations4.size(), 9);
EXPECT_EQ(mutations4[0].type, ShadowViewMutation::Update);
EXPECT_EQ(mutations4[0].oldChildShadowView.tag, 106);
EXPECT_EQ(mutations4[0].oldChildShadowView.tag, childG->getTag());
EXPECT_EQ(mutations4[1].type, ShadowViewMutation::Update);
EXPECT_EQ(mutations4[1].oldChildShadowView.tag, 107);
EXPECT_EQ(mutations4[1].oldChildShadowView.tag, childH->getTag());
EXPECT_EQ(mutations4[2].type, ShadowViewMutation::Update);
EXPECT_EQ(mutations4[2].oldChildShadowView.tag, 108);
EXPECT_EQ(mutations4[2].oldChildShadowView.tag, childI->getTag());
EXPECT_EQ(mutations4[3].type, ShadowViewMutation::Remove);
EXPECT_EQ(mutations4[3].oldChildShadowView.tag, 1000);
EXPECT_EQ(mutations4[3].oldChildShadowView.tag, reparentedViewA->getTag());
EXPECT_EQ(mutations4[4].type, ShadowViewMutation::Remove);
EXPECT_EQ(mutations4[4].oldChildShadowView.tag, 2000);
EXPECT_EQ(mutations4[4].oldChildShadowView.tag, reparentedViewB->getTag());
EXPECT_EQ(mutations4[5].type, ShadowViewMutation::Create);
EXPECT_EQ(mutations4[5].newChildShadowView.tag, 109);
EXPECT_EQ(mutations4[5].newChildShadowView.tag, childJ->getTag());
EXPECT_EQ(mutations4[6].type, ShadowViewMutation::Insert);
EXPECT_EQ(mutations4[6].newChildShadowView.tag, 109);
EXPECT_EQ(mutations4[6].newChildShadowView.tag, childJ->getTag());
EXPECT_EQ(mutations4[7].type, ShadowViewMutation::Insert);
EXPECT_EQ(mutations4[7].newChildShadowView.tag, 1000);
EXPECT_EQ(mutations4[7].newChildShadowView.tag, reparentedViewA->getTag());
EXPECT_EQ(mutations4[8].type, ShadowViewMutation::Insert);
EXPECT_EQ(mutations4[8].newChildShadowView.tag, 2000);
EXPECT_EQ(mutations4[8].newChildShadowView.tag, reparentedViewB->getTag());
}
} // namespace facebook::react
@@ -13,7 +13,7 @@
import type {RNTesterModule} from '../../types/RNTesterTypes';
import * as React from 'react';
import {StyleSheet, TextInput, View, Text} from 'react-native';
import {StyleSheet, Text, TextInput, View} from 'react-native';
const styles = StyleSheet.create({
contents: {
@@ -27,8 +27,8 @@ const {
StyleSheet,
Switch,
Text,
View,
TextInput,
View,
} = require('react-native');
class WithLabel extends React.Component<$FlowFixMeProps> {