] Add Fantom test placeholder for LogBox (#49252)

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

Changelog: [internal]

This adds a Fantom test placeholder for LogBox, which shows what type of tests we could be writing for this.

It also adds a few ids in LogBox components so we can inspect them in tests and make assertions on them.

Reviewed By: javache

Differential Revision: D69301572

fbshipit-source-id: 89a332a47c300c1dc18937cd91206ce6d820b6aa
This commit is contained in:
Rubén Norte
2025-02-07 07:47:32 -08:00
committed by Facebook GitHub Bot
parent b006080949
commit 10e47e69aa
9 changed files with 167 additions and 4 deletions
@@ -19,6 +19,7 @@ import * as LogBoxStyle from './LogBoxStyle';
import * as React from 'react';
type Props = $ReadOnly<{
id?: string,
backgroundColor: $ReadOnly<{
default: string,
pressed: string,
@@ -42,6 +43,7 @@ function LogBoxButton(props: Props): React.Node {
const content = (
<View
id={props.id}
style={StyleSheet.compose(
{
backgroundColor: pressed
@@ -36,7 +36,9 @@ export default function LogBoxInspectorHeader(props: Props): React.Node {
<LogBoxInspectorHeaderSafeArea style={styles[props.level]}>
<View style={styles.header}>
<View style={styles.title}>
<Text style={styles.titleText}>Failed to compile</Text>
<Text style={styles.titleText} id="logbox_header_title_text">
Failed to compile
</Text>
</View>
</View>
</LogBoxInspectorHeaderSafeArea>
@@ -60,7 +62,9 @@ export default function LogBoxInspectorHeader(props: Props): React.Node {
onPress={() => props.onSelectIndex(prevIndex)}
/>
<View style={styles.title}>
<Text style={styles.titleText}>{titleText}</Text>
<Text style={styles.titleText} id="logbox_header_title_text">
{titleText}
</Text>
</View>
<LogBoxInspectorHeaderButton
disabled={props.total <= 1}
@@ -46,11 +46,13 @@ function LogBoxInspectorMessageHeader(props: Props): React.Node {
return (
<View style={messageStyles.body}>
<View style={messageStyles.heading}>
<Text style={[messageStyles.headingText, messageStyles[props.level]]}>
<Text
style={[messageStyles.headingText, messageStyles[props.level]]}
id="logbox_message_title_text">
{props.title}
</Text>
</View>
<Text style={messageStyles.bodyText}>
<Text style={messageStyles.bodyText} id="logbox_message_contents_text">
<LogBoxMessage
maxLength={props.collapsed ? SHOW_MORE_MESSAGE_LENGTH : Infinity}
message={props.message}
@@ -39,6 +39,7 @@ export default function LogBoxNotification(props: Props): React.Node {
return (
<View style={styles.container}>
<LogBoxButton
id={`logbox_button_${level}`}
onPress={props.onPressOpen}
style={styles.press}
backgroundColor={{
@@ -36,6 +36,7 @@ exports[`LogBoxInspectorHeader should render both buttons for two total 1`] = `
}
>
<Text
id="logbox_header_title_text"
style={
Object {
"color": "rgba(255, 255, 255, 1)",
@@ -99,6 +100,7 @@ exports[`LogBoxInspectorHeader should render no buttons for one total 1`] = `
}
>
<Text
id="logbox_header_title_text"
style={
Object {
"color": "rgba(255, 255, 255, 1)",
@@ -152,6 +154,7 @@ exports[`LogBoxInspectorHeader should render syntax error header 1`] = `
}
>
<Text
id="logbox_header_title_text"
style={
Object {
"color": "rgba(255, 255, 255, 1)",
@@ -205,6 +208,7 @@ exports[`LogBoxInspectorHeader should render two buttons for three or more total
}
>
<Text
id="logbox_header_title_text"
style={
Object {
"color": "rgba(255, 255, 255, 1)",
@@ -28,6 +28,7 @@ exports[`LogBoxInspectorMessageHeader should not render "See More" if expanded 1
}
>
<Text
id="logbox_message_title_text"
style={
Array [
Object {
@@ -47,6 +48,7 @@ exports[`LogBoxInspectorMessageHeader should not render "See More" if expanded 1
</Text>
</View>
<Text
id="logbox_message_contents_text"
style={
Object {
"color": "rgba(255, 255, 255, 1)",
@@ -105,6 +107,7 @@ exports[`LogBoxInspectorMessageHeader should not render See More button for shor
}
>
<Text
id="logbox_message_title_text"
style={
Array [
Object {
@@ -124,6 +127,7 @@ exports[`LogBoxInspectorMessageHeader should not render See More button for shor
</Text>
</View>
<Text
id="logbox_message_contents_text"
style={
Object {
"color": "rgba(255, 255, 255, 1)",
@@ -182,6 +186,7 @@ exports[`LogBoxInspectorMessageHeader should render "See More" if collapsed 1`]
}
>
<Text
id="logbox_message_title_text"
style={
Array [
Object {
@@ -201,6 +206,7 @@ exports[`LogBoxInspectorMessageHeader should render "See More" if collapsed 1`]
</Text>
</View>
<Text
id="logbox_message_contents_text"
style={
Object {
"color": "rgba(255, 255, 255, 1)",
@@ -272,6 +278,7 @@ exports[`LogBoxInspectorMessageHeader should render error 1`] = `
}
>
<Text
id="logbox_message_title_text"
style={
Array [
Object {
@@ -291,6 +298,7 @@ exports[`LogBoxInspectorMessageHeader should render error 1`] = `
</Text>
</View>
<Text
id="logbox_message_contents_text"
style={
Object {
"color": "rgba(255, 255, 255, 1)",
@@ -349,6 +357,7 @@ exports[`LogBoxInspectorMessageHeader should render fatal 1`] = `
}
>
<Text
id="logbox_message_title_text"
style={
Array [
Object {
@@ -368,6 +377,7 @@ exports[`LogBoxInspectorMessageHeader should render fatal 1`] = `
</Text>
</View>
<Text
id="logbox_message_contents_text"
style={
Object {
"color": "rgba(255, 255, 255, 1)",
@@ -426,6 +436,7 @@ exports[`LogBoxInspectorMessageHeader should render syntax error 1`] = `
}
>
<Text
id="logbox_message_title_text"
style={
Array [
Object {
@@ -445,6 +456,7 @@ exports[`LogBoxInspectorMessageHeader should render syntax error 1`] = `
</Text>
</View>
<Text
id="logbox_message_contents_text"
style={
Object {
"color": "rgba(255, 255, 255, 1)",
@@ -20,6 +20,7 @@ exports[`LogBoxNotification should render log 1`] = `
"pressed": "rgba(51, 51, 51, 0.9)",
}
}
id="logbox_button_warn"
onPress={[Function]}
style={
Object {
@@ -0,0 +1,136 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
* @oncall react_native
* @fantom_flags enableAccessToHostTreeInFabric:true
*/
import ensureInstance from '../../../src/private/utilities/ensureInstance';
import ReadOnlyElement from '../../../src/private/webapis/dom/nodes/ReadOnlyElement';
import View from '../../Components/View/View';
import AppContainer from '../../ReactNative/AppContainer';
import LogBoxInspectorContainer from '../LogBoxInspectorContainer';
import {
ManualConsoleError,
// $FlowExpectedError[untyped-import]
} from './__fixtures__/ReactWarningFixtures';
import Fantom from '@react-native/fantom';
import nullthrows from 'nullthrows';
import * as React from 'react';
import '../../Core/InitializeCore.js';
function findById(node: ReadOnlyElement, id: string): ?ReadOnlyElement {
if (node.id === id) {
return node;
}
for (const child of node.children) {
const found = findById(child, id);
if (found) {
return found;
}
}
return null;
}
describe('LogBox', () => {
let originalConsoleError;
let originalConsoleWarn;
let mockError;
let mockWarn;
beforeAll(() => {
originalConsoleError = console.error;
originalConsoleWarn = console.warn;
});
beforeEach(() => {
mockError = jest.fn((...args) => {
originalConsoleError(...args);
});
mockWarn = jest.fn((...args) => {
originalConsoleWarn(...args);
});
// $FlowExpectedError[cannot-write]
console.error = mockError;
// $FlowExpectedError[cannot-write]
console.warn = mockWarn;
});
afterEach(() => {
// $FlowExpectedError[cannot-write]
console.error = originalConsoleError;
// $FlowExpectedError[cannot-write]
console.warn = originalConsoleWarn;
});
it('renders an empty screen if there are no errors', () => {
const logBoxRoot = Fantom.createRoot();
Fantom.runTask(() => {
logBoxRoot.render(<LogBoxInspectorContainer />);
});
expect(logBoxRoot.getRenderedOutput().toJSX()).toBe(null);
});
it('handles a manual console.error without a component stack in LogBox', () => {
let maybeViewNode;
const logBoxRoot = Fantom.createRoot();
Fantom.runTask(() => {
logBoxRoot.render(
<View
ref={node => {
maybeViewNode = node;
}}>
<LogBoxInspectorContainer />
</View>,
);
});
expect(logBoxRoot.getRenderedOutput().toJSX()).toBe(null);
const logBoxRootNode = ensureInstance(maybeViewNode, ReadOnlyElement);
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<View
ref={node => {
maybeViewNode = node;
}}>
<AppContainer rootTag={root.getRootTag()}>
<ManualConsoleError />
</AppContainer>
</View>,
);
});
expect(logBoxRoot.getRenderedOutput().toJSX()).toBe(null);
const appRootNode = ensureInstance(maybeViewNode, ReadOnlyElement);
const logBoxButton = nullthrows(
findById(appRootNode, 'logbox_button_error'),
);
Fantom.dispatchNativeEvent(logBoxButton, 'click');
const headerTitle = findById(logBoxRootNode, 'logbox_header_title_text');
const messageTitle = findById(logBoxRootNode, 'logbox_message_title_text');
const messageContents = findById(
logBoxRootNode,
'logbox_message_contents_text',
);
expect(headerTitle?.textContent).toBe('Log 1 of 1');
expect(messageTitle?.textContent).toBe('Console Error');
expect(messageContents?.textContent).toBe('Manual console error');
});
});
@@ -5480,6 +5480,7 @@ exports[`public API should not change unintentionally Libraries/LogBox/UI/AnsiHi
exports[`public API should not change unintentionally Libraries/LogBox/UI/LogBoxButton.js 1`] = `
"type Props = $ReadOnly<{
id?: string,
backgroundColor: $ReadOnly<{
default: string,
pressed: string,